bitkeeper revision 1.161 (3e8827bfgvKhhIcTx5141jdvnhh7gg)
authorjws@cairnwell.research <jws@cairnwell.research>
Mon, 31 Mar 2003 11:34:23 +0000 (11:34 +0000)
committerjws@cairnwell.research <jws@cairnwell.research>
Mon, 31 Mar 2003 11:34:23 +0000 (11:34 +0000)
megaraid support (beta)
new include file version.h makes porting easier

.rootkeys
xen/drivers/scsi/megaraid.c [new file with mode: 0644]
xen/drivers/scsi/megaraid.h [new file with mode: 0644]
xen/include/xeno/version.h [new file with mode: 0644]

index 5cfbe6a9aab33aa74f4359a5385ede5dfbf512d1..746275c4d2352553cb41573b1088ebcf34bae230 100644 (file)
--- a/.rootkeys
+++ b/.rootkeys
 3ddb79beXZxwKh7cGyPfr40bhDyRrA xen/drivers/scsi/constants.h
 3e564120ZeinH9nf3IVSerB80T7dHg xen/drivers/scsi/hosts.c
 3ddb79beGiGljlTNq_kRnCBZECgC9Q xen/drivers/scsi/hosts.h
+3e8827bdE8FgsI-QxZ4zKzYTRmACOQ xen/drivers/scsi/megaraid.c
+3e8827bdEMIzjyF9OHnDRmJGp_O68g xen/drivers/scsi/megaraid.h
 3ddb79bexarQo1tQ541PPUyK9HXNDA xen/drivers/scsi/scsi.c
 3ddb79beBOiYxQUiWTHosepRlJyuGA xen/drivers/scsi/scsi.h
 3ddb79beVTYJj6_KMxYLJmCP7p9MuQ xen/drivers/scsi/scsi_dma.c
 3ddb79c2_m8lT9jDKse_tePj7zcnNQ xen/include/xeno/timex.h
 3ddb79c2e2C14HkndNEJlYwXaPrF5A xen/include/xeno/tqueue.h
 3ddb79c1-kVvF8cVa0k3ZHDdBMj01Q xen/include/xeno/types.h
+3e8827bdaqPeZAWGVOwswgY9bWSx4g xen/include/xeno/version.h
 3ddb79c2Ae5KpzhC9LCYG7mP_Vi4Aw xen/include/xeno/vif.h
 3ddb79c4YQCQ6r0xNLLu0jfbM7pVmA xen/net/Makefile
 3ddb79c4AkfDkTCw0comx4L8wsUOMg xen/net/dev.c
diff --git a/xen/drivers/scsi/megaraid.c b/xen/drivers/scsi/megaraid.c
new file mode 100644 (file)
index 0000000..26c25a1
--- /dev/null
@@ -0,0 +1,5534 @@
+/*===================================================================
+ *
+ *                    Linux MegaRAID device driver
+ *
+ * Copyright 2001  LSI Logic Corporation.
+ *
+ *              This program is free software; you can redistribute it and/or
+ *              modify it under the terms of the GNU General Public License
+ *              as published by the Free Software Foundation; either version
+ *              2 of the License, or (at your option) any later version.
+ *
+ * Version : v1.18d (Aug 7, 2002)
+ *
+ * Description: Linux device driver for LSI Logic MegaRAID controller
+ *
+ * Supported controllers: MegaRAID 418, 428, 438, 466, 762, 467, 471, 490
+ *                                      493.
+ * History:
+ *
+ * Version 0.90:
+ *     Original source contributed by Dell; integrated it into the kernel and
+ *     cleaned up some things.  Added support for 438/466 controllers.
+ * Version 0.91:
+ *     Aligned mailbox area on 16-byte boundary.
+ *     Added schedule() at the end to properly clean up.
+ *     Made improvements for conformity to linux driver standards.
+ *
+ * Version 0.92:
+ *     Added support for 2.1 kernels.
+ *         Reads from pci_dev struct, so it's not dependent on pcibios.
+ *         Added some missing virt_to_bus() translations.
+ *     Added support for SMP.
+ *         Changed global cli()'s to spinlocks for 2.1, and simulated
+ *          spinlocks for 2.0.
+ *     Removed setting of SA_INTERRUPT flag when requesting Irq.
+ *
+ * Version 0.92ac:
+ *     Small changes to the comments/formatting. Plus a couple of
+ *      added notes. Returned to the authors. No actual code changes
+ *      save printk levels.
+ *     8 Oct 98        Alan Cox <alan.cox@linux.org>
+ *
+ *     Merged with 2.1.131 source tree.
+ *     12 Dec 98       K. Baranowski <kgb@knm.org.pl>
+ *
+ * Version 0.93:
+ *     Added support for vendor specific ioctl commands (M_RD_IOCTL_CMD+xxh)
+ *     Changed some fields in MEGARAID struct to better values.
+ *     Added signature check for Rp controllers under 2.0 kernels
+ *     Changed busy-wait loop to be time-based
+ *     Fixed SMP race condition in isr
+ *     Added kfree (sgList) on release
+ *     Added #include linux/version.h to megaraid.h for hosts.h
+ *     Changed max_id to represent max logical drives instead of targets.
+ *
+ * Version 0.94:
+ *     Got rid of some excess locking/unlocking
+ *     Fixed slight memory corruption problem while memcpy'ing into mailbox
+ *     Changed logical drives to be reported as luns rather than targets
+ *     Changed max_id to 16 since it is now max targets/chan again.
+ *     Improved ioctl interface for upcoming megamgr
+ *
+ * Version 0.95:
+ *     Fixed problem of queueing multiple commands to adapter;
+ *       still has some strange problems on some setups, so still
+ *       defaults to single.  To enable parallel commands change
+ *       #define MULTI_IO in megaraid.h
+ *     Changed kmalloc allocation to be done in beginning.
+ *     Got rid of C++ style comments
+ *
+ * Version 0.96:
+ *     762 fully supported.
+ *
+ * Version 0.97:
+ *     Changed megaraid_command to use wait_queue.
+ *
+ * Version 1.00:
+ *     Checks to see if an irq occurred while in isr, and runs through
+ *       routine again.
+ *     Copies mailbox to temp area before processing in isr
+ *     Added barrier() in busy wait to fix volatility bug
+ *     Uses separate list for freed Scbs, keeps track of cmd state
+ *     Put spinlocks around entire queue function for now...
+ *     Full multi-io commands working stablely without previous problems
+ *     Added skipXX LILO option for Madrona motherboard support
+ *
+ * Version 1.01:
+ *     Fixed bug in mega_cmd_done() for megamgr control commands,
+ *       the host_byte in the result code from the scsi request to
+ *       scsi midlayer is set to DID_BAD_TARGET when adapter's
+ *       returned codes are 0xF0 and 0xF4.
+ *
+ * Version 1.02:
+ *     Fixed the tape drive bug by extending the adapter timeout value
+ *       for passthrough command to 60 seconds in mega_build_cmd().
+ *
+ * Version 1.03:
+ *    Fixed Madrona support.
+ *    Changed the adapter timeout value from 60 sec in 1.02 to 10 min
+ *      for bigger and slower tape drive.
+ *    Added driver version printout at driver loadup time
+ *
+ * Version 1.04
+ *    Added code for 40 ld FW support.
+ *    Added new ioctl command 0x81 to support NEW_READ/WRITE_CONFIG with
+ *      data area greater than 4 KB, which is the upper bound for data
+ *      tranfer through scsi_ioctl interface.
+ *    The additional 32 bit field for 64bit address in the newly defined
+ *      mailbox64 structure is set to 0 at this point.
+ *
+ * Version 1.05
+ *    Changed the queing implementation for handling SCBs and completed
+ *      commands.
+ *    Added spinlocks in the interrupt service routine to enable the driver
+ *      function in the SMP environment.
+ *    Fixed the problem of unnecessary aborts in the abort entry point, which
+ *      also enables the driver to handle large amount of I/O requests for
+ *      long duration of time.
+ * Version 1.06
+ *              Intel Release
+ * Version 1.07
+ *    Removed the usage of uaccess.h file for kernel versions less than
+ *    2.0.36, as this file is not present in those versions.
+ *
+ * Version 108
+ *    Modified mega_ioctl so that 40LD megamanager would run
+ *    Made some changes for 2.3.XX compilation , esp wait structures
+ *    Code merge between 1.05 and 1.06 .
+ *    Bug fixed problem with ioctl interface for concurrency between
+ *    8ld and 40ld firwmare
+ *    Removed the flawed semaphore logic for handling new config command
+ *    Added support for building own scatter / gather list for big user
+ *    mode buffers
+ *    Added /proc file system support ,so that information is available in
+ *    human readable format
+ *
+ * Version 1a08
+ *    Changes for IA64 kernels. Checked for CONFIG_PROC_FS flag
+ *
+ * Version 1b08
+ *    Include file changes.
+ * Version 1b08b
+ *    Change PCI ID value for the 471 card, use #defines when searching
+ *    for megaraid cards.
+ *
+ * Version 1.10
+ *
+ *      I) Changes made to make following ioctl commands work in 0x81 interface
+ *              a)DCMD_DELETE_LOGDRV
+ *              b)DCMD_GET_DISK_CONFIG
+ *              c)DCMD_DELETE_DRIVEGROUP
+ *              d)NC_SUBOP_ENQUIRY3
+ *              e)DCMD_CHANGE_LDNO
+ *              f)DCMD_CHANGE_LOOPID
+ *              g)DCMD_FC_READ_NVRAM_CONFIG
+ *      h)DCMD_WRITE_CONFIG
+ *      II) Added mega_build_kernel_sg function
+ *  III)Firmware flashing option added
+ *
+ * Version 1.10a
+ *
+ *      I)Dell updates included in the source code.
+ *              Note:   This change is not tested due to the unavailability of IA64 kernel
+ *      and it is in the #ifdef DELL_MODIFICATION macro which is not defined
+ *
+ * Version 1.10b
+ *
+ *      I)In M_RD_IOCTL_CMD_NEW command the wrong way of copying the data
+ *    to the user address corrected
+ *
+ * Version 1.10c
+ *
+ *      I) DCMD_GET_DISK_CONFIG opcode updated for the firmware changes.
+ *
+ * Version 1.11
+ *      I)  Version number changed from 1.10c to 1.11
+ *  II) DCMD_WRITE_CONFIG(0x0D) command in the driver changed from
+ *      scatter/gather list mode to direct pointer mode..
+ *     Fixed bug of undesirably detecting HP onboard controllers which
+ *       are disabled.
+ *
+ *      Version 1.12 (Sep 21, 2000)
+ *
+ *     I. Changes have been made for Dynamic DMA mapping in IA64 platform.
+ *                To enable all these changes define M_RD_DYNAMIC_DMA_SUPPORT in megaraid.h
+ *        II. Got rid of windows mode comments
+ *       III. Removed unwanted code segments
+ *    IV. Fixed bug of HP onboard controller information (commented with
+ *                 MEGA_HP_FIX)
+ *
+ *      Version 1a12
+ *      I.      reboot notifier and new ioctl changes ported from 1c09
+ *
+ *      Version 1b12
+ *      I.      Changes in new ioctl interface routines ( Nov 06, 2000 )
+ *
+ *      Version 1c12
+ *      I.      Changes in new ioctl interface routines ( Nov 07, 2000 )
+ *
+ *      Version 1d12
+ *      I.      Compilation error under kernel 2.4.0 for 32-bit machine in mega_ioctl
+ *
+ *      Version 1e12, 1f12
+ *      1.  Fixes for pci_map_single, pci_alloc_consistent along with mailbox
+ *          alignment
+ *
+ *     Version 1.13beta
+ *     Added Support for Full 64bit address space support. If firmware
+ *     supports 64bit, it goes to 64 bit mode even on x86 32bit 
+ *     systems. Data Corruption Issues while running on test9 kernel
+ *     on IA64 systems. This issue not seen on test11 on x86 system
+ *
+ *     Version 1.13c
+ *     1. Resolved Memory Leak when using M_RD_IOCTL_CMD interface
+ *     2. Resolved Queuing problem when MailBox Blocks
+ *     3. Added unregister_reboot_notifier support
+ * 
+ *     Version 1.13d
+ *     Experimental changes in interfacing with the controller in ISR
+ *
+ *     Version 1.13e
+ *     Fixed Broken 2.2.XX compilation changes + misc changes
+ *
+ *     Version 1.13f to 1.13i
+ *     misc changes + code clean up
+ *     Cleaned up the ioctl code and added set_mbox_xfer_addr()
+ *     Support for START_DEV (6)
+ *     
+ *     Version 1.13j
+ *     Moved some code to megaraid.h file, replaced some hard coded values 
+ *      with respective macros. Changed some functions to static
+ *
+ *     Version 1.13k
+ *     Only some idendation correction to 1.13j 
+ *
+ *     Version 1.13l , 1.13m, 1.13n, 1.13o
+ *     Minor Identation changes + misc changes
+ *
+ *     Version 1.13q
+ *     Paded the new uioctl_t MIMD structure for maintaining alignment 
+ *     and size across 32 / 64 bit platforms
+ *     Changed the way MIMD IOCTL interface used virt_to_bus() to use pci
+ *     memory location
+ *
+ *     Version 1.13r
+ *     2.4.xx SCSI Changes.
+ *
+ *     Version 1.13s
+ *     Stats counter fixes
+ *     Temporary fix for some 64 bit firmwares in 2.4.XX kernels
+ *
+ *     Version 1.13t
+ *     Support for 64bit version of READ/WRITE/VIEW DISK CONFIG
+ *
+ *     Version 1.14
+ *     Did away with MEGADEV_IOCTL flag. It is now standard part of driver
+ *     without need for a special #define flag
+ *     Disabled old scsi ioctl path for kernel versions > 2.3.xx. This is due
+ *     to the nature in which the new scsi code queues a new scsi command to 
+ *     controller during SCSI IO Completion
+ *     Driver now checks for sub-system vendor id before taking ownership of
+ *     the controller
+ *
+ *     Version 1.14a
+ *     Added Host re-ordering
+ *
+ *     Version 1.14b
+ *     Corrected some issue which caused the older cards not to work
+ *     
+ *     Version 1.14c
+ *     IOCTL changes for not handling the non-64bit firmwares under 2.4.XX
+ *     kernel
+ *
+ *     Version 1.14d
+ *     Fixed Various MIMD Synchronization Issues
+ *     
+ *     Version 1.14e
+ *     Fixed the error handling during card initialization
+ *
+ *     Version 1.14f
+ *     Multiple invocations of mimd phase I ioctl stalls the cpu. Replaced
+ *     spinlock with semaphore(mutex)
+ *
+ *     Version 1.14g
+ *     Fixed running out of scbs issues while running MIMD apps under heavy IO
+ *
+ *     Version 1.14g-ac - 02/03/01
+ *     Reformatted to Linux format so I could compare to old one and cross
+ *     check bug fixes
+ *     Re fixed the assorted missing 'static' cases
+ *     Removed some unneeded version checks
+ *     Cleaned up some of the VERSION checks in the code
+ *     Left 2.0 support but removed 2.1.x support.
+ *     Collected much of the compat glue into one spot
+ *
+ *     Version 1.14g-ac2 - 22/03/01
+ *     Fixed a non obvious dereference after free in the driver unload path
+ *
+ *     Version 1.14i
+ *     changes for making 32bit application run on IA64
+ *
+ *     Version 1.14j
+ *     Tue Mar 13 14:27:54 EST 2001 - AM
+ *     Changes made in the driver to be able to run applications if the
+ *     system has memory >4GB.
+ *
+ *
+ *     Version 1.14k
+ *     Thu Mar 15 18:38:11 EST 2001 - AM
+ *
+ *     Firmware version check removed if subsysid==0x1111 and
+ *     subsysvid==0x1111, since its not yet initialized.
+ *
+ *     changes made to correctly calculate the base in mega_findCard.
+ *
+ *     Driver informational messages now appear on the console as well as
+ *     with dmesg
+ *
+ *     Older ioctl interface is returned failure on newer(2.4.xx) kernels.
+ *
+ *     Inclusion of "modversions.h" is still a debatable question. It is
+ *     included anyway with this release.
+ *
+ *     Version 1.14l
+ *     Mon Mar 19 17:39:46 EST 2001 - AM
+ *
+ *     Assorted changes to remove compilation error in 1.14k when compiled
+ *     with kernel < 2.4.0
+ *
+ *     Version 1.14m
+ *     Tue Mar 27 12:09:22 EST 2001 - AM
+ *
+ *     Added support for extended CDBs ( > 10 bytes ) and OBDR ( One Button
+ *     Disaster Recovery ) feature.
+ *
+ *
+ *     Version 1.14n
+ *     Tue Apr 10 14:28:13 EDT 2001 - AM
+ *
+ *     "modeversions.h" is no longer included in the code.
+ *     2.4.xx style mutex initialization used for older kernels also
+ *
+ *     Version 1.14o
+ *     Wed Apr 18 17:47:26 EDT 2001 - PJ
+ *
+ *     Before returning status for 'inquiry', we first check if request buffer
+ *     is SG list, and then return appropriate status
+ *
+ *     Version 1.14p
+ *     Wed Apr 25 13:44:48 EDT 2001 - PJ
+ *
+ *     SCSI result made appropriate in case of check conditions for extended
+ *     passthru commands
+ *
+ *     Do not support lun >7 for physically accessed devices 
+ *
+ *     
+ *     Version 1.15
+ *     Thu Apr 19 09:38:38 EDT 2001 - AM
+ *
+ *     1.14l rollover to 1.15 - merged with main trunk after 1.15d
+ *
+ *     Version 1.15b
+ *  Wed May 16 20:10:01 EDT 2001 - AM
+ *
+ *     "modeversions.h" is no longer included in the code.
+ *     2.4.xx style mutex initialization used for older kernels also
+ *     Brought in-sync with Alan's changes in 2.4.4
+ *     Note: 1.15a is on OBDR branch(main trunk), and is not merged with yet.
+ *
+ * Version 1.15c
+ * Mon May 21 23:10:42 EDT 2001 - AM
+ *
+ * ioctl interface uses 2.4.x conforming pci dma calls
+ * similar calls used for older kernels
+ *
+ * Version 1.15d
+ * Wed May 30 17:30:41 EDT 2001 - AM
+ *
+ * NULL is not a valid first argument for pci_alloc_consistent() on
+ * IA64(2.4.3-2.10.1). Code shuffling done in ioctl interface to get
+ * "pci_dev" before making calls to pci interface routines.
+ *
+ * Version 1.16pre
+ * Fri Jun  1 19:40:48 EDT 2001 - AM
+ *
+ * 1.14p and 1.15d merged
+ * ROMB support added
+ *
+ * Version 1.16-pre1
+ * Mon Jun  4 15:01:01 EDT 2001 - AM
+ *
+ * Non-ROMB firmware do no DMA support 0xA9 command. Value 0xFF
+ * (all channels are raid ) is chosen for those firmware.
+ *
+ * Version 1.16-pre2
+ * Mon Jun 11 18:15:31 EDT 2001 - AM
+ *
+ * Changes for boot from any logical drive
+ *
+ * Version 1.16
+ * Tue Jun 26 18:07:02 EDT 2001 - AM
+ *
+ * branched at 1.14p
+ *
+ * Check added for HP 1M/2M controllers if having firmware H.01.07 or
+ * H.01.08. If found, disable 64 bit support since these firmware have
+ * limitations for 64 bit addressing
+ *
+ *
+ * Version 1.17
+ * Thu Jul 12 11:14:09 EDT 2001 - AM
+ *
+ * 1.16pre2 and 1.16 merged.
+ *
+ * init_MUTEX and init_MUTEX_LOCKED are defined in 2.2.19. Pre-processor
+ * statements are added for them
+ *
+ * Linus's 2.4.7pre3 kernel introduces a new field 'max_sectors' in Scsi_Host
+ * structure, to improve IO performance.
+ *
+ *
+ * Version 1.17a
+ * Fri Jul 13 18:44:01 EDT 2001 - AM
+ *
+ * Starting from kernel 2.4.x, LUN is not < 8 - following SCSI-III. So to have
+ * our current formula working to calculate logical drive number, return
+ * failure for LUN > 7
+ *
+ *
+ * Version 1.17b
+ * Mon Jul 30 19:24:02 EDT 2001 - AM
+ *
+ * Added support for random deletion of logical drives
+ *
+ * Version 1.17c
+ * Tue Sep 25 09:37:49 EDT 2001 - Atul Mukker <atulm@lsil.com>
+ *
+ * With single and dual channel controllers, some virtaul channels are
+ * displayed negative.
+ *
+ * Version 1.17a-ac
+ * Mon Aug 6 14:59:29 BST 2001 - "Michael Johnson" <johnsom@home.com>
+ *
+ * Make the HP print formatting and check for buggy firmware runtime not
+ * ifdef dependant.
+ *
+ *
+ * Version 1.17d
+ * Thu Oct 11 10:48:45 EDT 2001 - Atul Mukker <atulm@lsil.com>
+ *
+ * Driver 1.17c oops when loaded without controller.
+ *
+ * Special case for "use_sg == 1" removed while building the scatter gather
+ * list.
+ *
+ * Version 1.18
+ * Thu Oct 11 15:02:53 EDT 2001 - Atul Mukker <atulm@lsil.com>
+ *
+ * References to AMI have been changed to LSI Logic.
+ *
+ * Version 1.18a
+ * Mon Mar 11 11:38:38 EST 2002 - Atul Mukker <Atul.Mukker@lsil.com>
+ *
+ * RAID On MotherBoard (ROMB) - boot from logical or physical drives
+ *
+ * Support added for discovery(ROMB) vendor and device ids.
+ *
+ * Data transfer length for passthru commands must be valid even if the
+ * command has an associated scatter-gather list.
+ *
+ *
+ * Version 1.18b
+ * Tue Apr 23 11:01:58 EDT 2002 - Atul Mukker <Atul.Mukker@lsil.com>
+ *
+ * typo corrected for scsi condition CHECK_CONDITION in mega_cmd_done()
+ *
+ * Support added for PCI_VENDOR_ID_LSI_LOGIC with device id
+ * PCI_DEVICE_ID_AMI_MEGARAID3.
+ *
+ *
+ * Version 1.18c
+ * Thu May 16 10:27:55 EDT 2002 - Atul Mukker <Atul.Mukker@lsil.com>
+ *
+ * Retrun valid return status for mega passthru commands resulting in
+ * contingent allegiance condition. Check for 64-bit passthru commands also.
+ *
+ * Do not check_region() anymore and check for return value of
+ * request_region()
+ *
+ * Send valid sense data to appliations using the private ioctl interface.
+ *
+ *
+ * Version 1.18d
+ * Wed Aug  7 18:51:51 EDT 2002 - Atul Mukker <atul.mukker@lsil.com>
+ *
+ * Added support for yellowstone and verde controller
+ *
+ *
+ * BUGS:
+ *     Some older 2.1 kernels (eg. 2.1.90) have a bug in pci.c that
+ *     fails to detect the controller as a pci device on the system.
+ *
+ *     Timeout period for upper scsi layer, i.e. SD_TIMEOUT in
+ *     /drivers/scsi/sd.c, is too short for this controller. SD_TIMEOUT
+ *     value must be increased to (30 * HZ) otherwise false timeouts
+ *     will occur in the upper layer.
+ *
+ *     Never set skip_id. The existing PCI code the megaraid uses fails
+ *     to properly check the vendor subid in some cases. Setting this then
+ *     makes it steal other i960's and crashes some boxes
+ *
+ *     Far too many ifdefs for versions.
+ *
+ *===================================================================*/
+
+
+#include <xeno/config.h>
+#include <xeno/version.h>
+#include <xeno/module.h>
+#include <xeno/types.h>
+#include <xeno/errno.h>
+#include <xeno/string.h>
+#include <xeno/lib.h>
+#include <xeno/kernel.h>
+#include <xeno/ioport.h>
+//#include <xeno/fcntl.h>
+#include <xeno/delay.h>
+#include <xeno/pci.h>
+//#include <xeno/proc_fs.h>
+#include <xeno/blk.h>
+//#include <xeno/wait.h>
+#include <xeno/tqueue.h>
+#include <xeno/interrupt.h>
+#include <xeno/mm.h>
+//#include <asm/pgtable.h>
+
+#include <asm/ioctl.h>
+#include <xeno/sched.h>
+//#include <xeno/stat.h>
+#include <xeno/slab.h> /* for kmalloc() */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0) /* 0x20100 */
+#include <xeno/bios32.h>
+#else
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) /* 0x20300 */
+#include <asm/spinlock.h>
+#else
+#include <xeno/spinlock.h>
+#endif
+#endif
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,0,24)        /* 0x020024 */
+#include <asm/uaccess.h>
+#endif
+
+/*
+ * These header files are required for Shutdown Notification routines
+ */
+#include <xeno/notifier.h>
+#include <xeno/reboot.h>
+#include <xeno/init.h>
+
+#include "sd.h"
+#include "scsi.h"
+#include "hosts.h"
+
+#include "megaraid.h"
+
+/*
+ *================================================================
+ *  #Defines
+ *================================================================
+ */
+
+#define MAX_SERBUF 160
+#define COM_BASE 0x2f8
+
+static ulong RDINDOOR (mega_host_config * megaCfg)
+{
+       return readl (megaCfg->base + 0x20);
+}
+
+static void WRINDOOR (mega_host_config * megaCfg, ulong value)
+{
+       writel (value, megaCfg->base + 0x20);
+}
+
+static ulong RDOUTDOOR (mega_host_config * megaCfg)
+{
+       return readl (megaCfg->base + 0x2C);
+}
+
+static void WROUTDOOR (mega_host_config * megaCfg, ulong value)
+{
+       writel (value, megaCfg->base + 0x2C);
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)        /* 0x020200 */
+#include <xeno/smp.h>
+#define cpuid smp_processor_id()
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4)
+#define scsi_set_pci_device(x,y)
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)        /* 0x020400 */
+
+/*
+ *     Linux 2.4 and higher
+ *
+ *     No driver private lock
+ *     Use the io_request_lock not cli/sti
+ *     queue task is a simple api without irq forms
+ */
+
+MODULE_AUTHOR ("LSI Logic Corporation");
+MODULE_DESCRIPTION ("LSI Logic MegaRAID driver");
+MODULE_LICENSE ("GPL");
+
+#define DRIVER_LOCK_T
+#define DRIVER_LOCK_INIT(p)
+#define DRIVER_LOCK(p)
+#define DRIVER_UNLOCK(p)
+#define IO_LOCK_T unsigned long io_flags = 0
+#define IO_LOCK spin_lock_irqsave(&io_request_lock,io_flags);
+#define IO_UNLOCK spin_unlock_irqrestore(&io_request_lock,io_flags);
+
+#define queue_task_irq(a,b)     queue_task(a,b)
+#define queue_task_irq_off(a,b) queue_task(a,b)
+
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)      /* 0x020200 */
+
+/*
+ *     Linux 2.2 and higher
+ *
+ *     No driver private lock
+ *     Use the io_request_lock not cli/sti
+ *     No pci region api
+ *     queue_task is now a single simple API
+ */
+
+static char kernel_version[] = UTS_RELEASE;
+MODULE_AUTHOR ("LSI Logic Corporation");
+MODULE_DESCRIPTION ("LSI Logic MegaRAID driver");
+
+#define DRIVER_LOCK_T
+#define DRIVER_LOCK_INIT(p)
+#define DRIVER_LOCK(p)
+#define DRIVER_UNLOCK(p)
+#define IO_LOCK_T unsigned long io_flags = 0
+#define IO_LOCK spin_lock_irqsave(&io_request_lock,io_flags);
+#define IO_UNLOCK spin_unlock_irqrestore(&io_request_lock,io_flags);
+
+#define pci_free_consistent(a,b,c,d)
+#define pci_unmap_single(a,b,c,d)
+#define pci_enable_device(x) (0)
+#define queue_task_irq(a,b)     queue_task(a,b)
+#define queue_task_irq_off(a,b) queue_task(a,b)
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,19)        /* 0x020219 */
+#define init_MUTEX_LOCKED(x)    (*(x)=MUTEX_LOCKED)
+#define init_MUTEX(x)           (*(x)=MUTEX)
+#define DECLARE_WAIT_QUEUE_HEAD(x)     struct wait_queue *x = NULL
+#endif
+
+
+#else
+
+/*
+ *     Linux 2.0 macros. Here we have to provide some of our own
+ *     functionality. We also only work little endian 32bit.
+ *     Again no pci_alloc/free api
+ *     IO_LOCK/IO_LOCK_T were never used in 2.0 so now are empty 
+ */
+#define cpuid 0
+#define DRIVER_LOCK_T long cpu_flags;
+#define DRIVER_LOCK_INIT(p)
+#define DRIVER_LOCK(p) \
+                       save_flags(cpu_flags); \
+                       cli();
+#define DRIVER_UNLOCK(p) \
+                       restore_flags(cpu_flags);
+#define IO_LOCK_T
+#define IO_LOCK(p)
+#define IO_UNLOCK(p)
+#define le32_to_cpu(x) (x)
+#define cpu_to_le32(x) (x)
+
+#define pci_free_consistent(a,b,c,d)
+#define pci_unmap_single(a,b,c,d)
+
+#define init_MUTEX_LOCKED(x)    (*(x)=MUTEX_LOCKED)
+#define init_MUTEX(x)           (*(x)=MUTEX)
+
+#define pci_enable_device(x) (0)
+
+/*
+ *     2.0 lacks spinlocks, iounmap/ioremap
+ */
+
+#define ioremap vremap
+#define iounmap vfree
+
+ /* simulate spin locks */
+typedef struct {
+       volatile char lock;
+} spinlock_t;
+
+#define spin_lock_init(x) { (x)->lock = 0;}
+#define spin_lock_irqsave(x,flags) { while ((x)->lock) barrier();\
+                                        (x)->lock=1; save_flags(flags);\
+                                        cli();}
+#define spin_unlock_irqrestore(x,flags) { (x)->lock=0; restore_flags(flags);}
+
+#define DECLARE_WAIT_QUEUE_HEAD(x)     struct wait_queue *x = NULL
+
+#endif
+
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)        /* 0x020400 */
+#define dma_alloc_consistent pci_alloc_consistent
+#define dma_free_consistent pci_free_consistent
+#else
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,19)        /* 0x020219 */
+typedef unsigned long dma_addr_t;
+#endif
+void *dma_alloc_consistent(void *, size_t, dma_addr_t *);
+void dma_free_consistent(void *, size_t, void *, dma_addr_t);
+int mega_get_order(int);
+int pow_2(int);
+#endif
+
+/* set SERDEBUG to 1 to enable serial debugging */
+#define SERDEBUG 0
+#if SERDEBUG
+static void ser_init (void);
+static void ser_puts (char *str);
+static void ser_putc (char c);
+static int ser_printk (const char *fmt, ...);
+#endif
+
+#ifdef CONFIG_PROC_FS
+#define COPY_BACK if (offset > megaCfg->procidx) { \
+               *eof = TRUE; \
+        megaCfg->procidx = 0; \
+        megaCfg->procbuf[0] = 0; \
+        return 0;} \
+ if ((count + offset) > megaCfg->procidx) { \
+      count = megaCfg->procidx - offset; \
+      *eof = TRUE; } \
+      memcpy(page, &megaCfg->procbuf[offset], count); \
+      megaCfg->procidx = 0; \
+      megaCfg->procbuf[0] = 0;
+#endif
+
+/*
+ * ================================================================
+ *                    Global variables
+ *================================================================
+ */
+
+/*  Use "megaraid=skipXX" as LILO option to prohibit driver from scanning
+    XX scsi id on each channel.  Used for Madrona motherboard, where SAF_TE
+    processor id cannot be scanned */
+
+static char *megaraid;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,0) /* 0x20100 */
+#ifdef MODULE
+MODULE_PARM (megaraid, "s");
+#endif
+#endif
+static int skip_id = -1;
+static int numCtlrs = 0;
+static mega_host_config *megaCtlrs[FC_MAX_CHANNELS] = { 0 };
+#if XENO_KILLED
+static struct proc_dir_entry *mega_proc_dir_entry;
+#endif
+
+#if DEBUG
+static u32 maxCmdTime = 0;
+#endif
+
+static mega_scb *pLastScb = NULL;
+#if XENO_KILLED
+static struct notifier_block mega_notifier = {
+       megaraid_reboot_notify,
+       NULL,
+       0
+};
+#endif
+
+/* For controller re-ordering */
+struct mega_hbas mega_hbas[MAX_CONTROLLERS];
+
+/*
+ * The File Operations structure for the serial/ioctl interface of the driver
+ */
+/* For controller re-ordering */ 
+#if XENO_KILLED
+static struct file_operations megadev_fops = {
+       ioctl:megadev_ioctl_entry,
+       open:megadev_open,
+       release:megadev_close,
+};
+#endif
+/*
+ * Array to structures for storing the information about the controllers. This
+ * information is sent to the user level applications, when they do an ioctl
+ * for this information.
+ */
+static struct mcontroller mcontroller[MAX_CONTROLLERS];
+
+/* The current driver version */
+static u32 driver_ver = 0x118C;
+
+#if XENO_KILLED
+/* major number used by the device for character interface */
+static int major;
+
+static struct semaphore mimd_ioctl_sem;
+static struct semaphore mimd_entry_mtx;
+#endif
+
+#if SERDEBUG
+volatile static spinlock_t serial_lock;
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) /* 0x20300 */
+static struct proc_dir_entry proc_scsi_megaraid = {
+       PROC_SCSI_MEGARAID, 8, "megaraid",
+       S_IFDIR | S_IRUGO | S_IXUGO, 2
+};
+#endif
+
+#ifdef CONFIG_PROC_FS
+extern struct proc_dir_entry proc_root;
+#endif
+
+#define        IS_RAID_CH(this, ch)    ( (this->mega_ch_class >> (ch)) & 0x01 )
+
+#if SERDEBUG
+static char strbuf[MAX_SERBUF + 1];
+
+static void ser_init (void)
+{
+       unsigned port = COM_BASE;
+
+       outb (0x80, port + 3);
+       outb (0, port + 1);
+       /* 9600 Baud, if 19200: outb(6,port) */
+       outb (12, port);
+       outb (3, port + 3);
+       outb (0, port + 1);
+}
+
+static void ser_puts (char *str)
+{
+       char *ptr;
+
+       ser_init ();
+       for (ptr = str; *ptr; ++ptr)
+               ser_putc (*ptr);
+}
+
+static void ser_putc (char c)
+{
+       unsigned port = COM_BASE;
+
+       while ((inb (port + 5) & 0x20) == 0) ;
+       outb (c, port);
+       if (c == 0x0a) {
+               while ((inb (port + 5) & 0x20) == 0) ;
+               outb (0x0d, port);
+       }
+}
+
+static int ser_printk (const char *fmt, ...)
+{
+       va_list args;
+       int i;
+       long flags;
+
+       spin_lock_irqsave (&serial_lock, flags);
+       va_start (args, fmt);
+       i = vsprintf (strbuf, fmt, args);
+       ser_puts (strbuf);
+       va_end (args);
+       spin_unlock_irqrestore (&serial_lock, flags);
+
+       return i;
+}
+
+#define TRACE(a)    { ser_printk a;}
+
+#else
+#define TRACE(A)
+#endif
+
+#define TRACE1(a)
+
+static void callDone (Scsi_Cmnd * SCpnt)
+{
+       if (SCpnt->result) {
+               TRACE (("*** %.08lx %.02x <%d.%d.%d> = %x\n",
+                       SCpnt->serial_number, SCpnt->cmnd[0], SCpnt->channel,
+                       SCpnt->target, SCpnt->lun, SCpnt->result));
+       }
+       SCpnt->scsi_done (SCpnt);
+}
+
+/*-------------------------------------------------------------------------
+ *
+ *                      Local functions
+ *
+ *-------------------------------------------------------------------------*/
+
+/*=======================
+ * Free a SCB structure
+ *=======================
+ */
+static void mega_freeSCB (mega_host_config * megaCfg, mega_scb * pScb)
+{
+
+       mega_scb *pScbtmp;
+
+       if ((pScb == NULL) || (pScb->idx >= 0xFE)) {
+               return;
+       }
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+       switch (pScb->dma_type) {
+       case M_RD_DMA_TYPE_NONE:
+               break;
+       case M_RD_PTHRU_WITH_BULK_DATA:
+               pci_unmap_single (megaCfg->dev, pScb->dma_h_bulkdata,
+                                 pScb->pthru->dataxferlen,
+                                 pScb->dma_direction);
+               break;
+       case M_RD_EPTHRU_WITH_BULK_DATA:
+               pci_unmap_single (megaCfg->dev, pScb->dma_h_bulkdata,
+                                 pScb->epthru->dataxferlen,
+                                 pScb->dma_direction);
+               break;
+       case M_RD_PTHRU_WITH_SGLIST:
+       {
+               int count;
+               for (count = 0; count < pScb->sglist_count; count++) {
+                       pci_unmap_single (megaCfg->dev,
+                                         pScb->dma_h_sglist[count],
+                                         pScb->sgList[count].length,
+                                         pScb->dma_direction);
+
+               }
+               break;
+       }
+       case M_RD_BULK_DATA_ONLY:
+               pci_unmap_single (megaCfg->dev,
+                                 pScb->dma_h_bulkdata,
+                                 pScb->iDataSize, pScb->dma_direction);
+
+               break;
+       case M_RD_SGLIST_ONLY:
+               pci_unmap_sg (megaCfg->dev,
+                             pScb->SCpnt->request_buffer,
+                             pScb->SCpnt->use_sg, pScb->dma_direction);
+               break;
+       default:
+               break;
+       }
+#endif
+
+       /* Unlink from pending queue */
+       if (pScb == megaCfg->qPendingH) {
+
+               if (megaCfg->qPendingH == megaCfg->qPendingT)
+                       megaCfg->qPendingH = megaCfg->qPendingT = NULL;
+               else
+                       megaCfg->qPendingH = megaCfg->qPendingH->next;
+
+               megaCfg->qPcnt--;
+
+       } else {
+               for (pScbtmp = megaCfg->qPendingH; pScbtmp;
+                    pScbtmp = pScbtmp->next) {
+
+                       if (pScbtmp->next == pScb) {
+
+                               pScbtmp->next = pScb->next;
+
+                               if (pScb == megaCfg->qPendingT) {
+                                       megaCfg->qPendingT = pScbtmp;
+                               }
+
+                               megaCfg->qPcnt--;
+                               break;
+                       }
+               }
+       }
+
+       /* Link back into free list */
+       pScb->state = SCB_FREE;
+       pScb->SCpnt = NULL;
+
+       if (megaCfg->qFreeH == (mega_scb *) NULL) {
+               megaCfg->qFreeH = megaCfg->qFreeT = pScb;
+       } else {
+               megaCfg->qFreeT->next = pScb;
+               megaCfg->qFreeT = pScb;
+       }
+
+       megaCfg->qFreeT->next = NULL;
+       megaCfg->qFcnt++;
+
+}
+
+/*===========================
+ * Allocate a SCB structure
+ *===========================
+ */
+static mega_scb *mega_allocateSCB (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt)
+{
+       mega_scb *pScb;
+
+       /* Unlink command from Free List */
+       if ((pScb = megaCfg->qFreeH) != NULL) {
+               megaCfg->qFreeH = pScb->next;
+               megaCfg->qFcnt--;
+
+               pScb->isrcount = jiffies;
+               pScb->next = NULL;
+               pScb->state = SCB_ACTIVE;
+               pScb->SCpnt = SCpnt;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+               pScb->dma_type = M_RD_DMA_TYPE_NONE;
+#endif
+
+               return pScb;
+       }
+
+       printk (KERN_WARNING "Megaraid: Could not allocate free SCB!!!\n");
+
+       return NULL;
+}
+
+/* Run through the list of completed requests  and finish it */
+static void mega_rundoneq (mega_host_config * megaCfg)
+{
+       Scsi_Cmnd *SCpnt;
+
+       while ((SCpnt = megaCfg->qCompletedH) != NULL) {
+               megaCfg->qCompletedH = (Scsi_Cmnd *) SCpnt->host_scribble;
+               megaCfg->qCcnt--;
+
+               SCpnt->host_scribble = (unsigned char *) NULL;  /* XC : sep 14 */
+               /* Callback */
+               callDone (SCpnt);
+       }
+
+       megaCfg->qCompletedH = megaCfg->qCompletedT = NULL;
+}
+
+/*
+ * Runs through the list of pending requests
+ * Assumes that mega_lock spin_lock has been acquired.
+ */
+static int mega_runpendq (mega_host_config * megaCfg)
+{
+       mega_scb *pScb;
+       int rc;
+
+       /* Issue any pending commands to the card */
+       for (pScb = megaCfg->qPendingH; pScb; pScb = pScb->next) {
+               if (pScb->state == SCB_ACTIVE) {
+                       if ((rc =
+                            megaIssueCmd (megaCfg, pScb->mboxData, pScb, 1)) == -1)
+                               return rc;
+               }
+       }
+       return 0;
+}
+
+/* Add command to the list of completed requests */
+
+static void mega_cmd_done (mega_host_config * megaCfg, mega_scb * pScb, int status)
+{
+       int islogical;
+       Scsi_Cmnd *SCpnt;
+       mega_passthru *pthru;
+       mega_ext_passthru *epthru;
+       mega_mailbox *mbox;
+       struct scatterlist *sgList;
+       u8      c;
+
+       if (pScb == NULL) {
+               TRACE (("NULL pScb in mega_cmd_done!"));
+               printk(KERN_CRIT "NULL pScb in mega_cmd_done!");
+       }
+
+       SCpnt = pScb->SCpnt;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+       pthru = pScb->pthru;
+       epthru = pScb->epthru;
+#else
+       pthru = &pScb->pthru;
+       epthru = &pScb->epthru;
+#endif
+
+       mbox = (mega_mailbox *) & pScb->mboxData;
+
+       if (SCpnt == NULL) {
+               TRACE (("NULL SCpnt in mega_cmd_done!"));
+               TRACE (("pScb->idx = ", pScb->idx));
+               TRACE (("pScb->state = ", pScb->state));
+               TRACE (("pScb->state = ", pScb->state));
+               panic(KERN_ERR "megaraid:Problem...!\n");
+       }
+
+#if 0
+       islogical = ( (SCpnt->channel >= megaCfg->productInfo.SCSIChanPresent) &&
+                                       (SCpnt->channel <= megaCfg->host->max_channel) );
+#endif
+#if 0
+       islogical = (SCpnt->channel == megaCfg->host->max_channel);
+#endif
+       islogical = megaCfg->logdrv_chan[SCpnt->channel];
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+       /* Special Case to handle PassThrough->XferAddrress > 4GB */
+       switch (SCpnt->cmnd[0]) {
+       case INQUIRY:
+       case READ_CAPACITY:
+               memcpy (SCpnt->request_buffer,
+                       pScb->bounce_buffer, SCpnt->request_bufflen);
+               break;
+       }
+#endif
+
+       mega_freeSCB (megaCfg, pScb);
+
+       /*
+        * Do not return the presence of hard disk on the channel so, inquiry
+        * sent, and returned data==hard disk or removable hard disk and not
+        * logical, request should return failure! - PJ
+        */
+#if 0
+       if (SCpnt->cmnd[0] == INQUIRY && ((((u_char *) SCpnt->request_buffer)[0] & 0x1F) == TYPE_DISK) && !islogical) {
+               status = 0xF0;
+       }
+#endif
+       if (SCpnt->cmnd[0] == INQUIRY && !islogical) {
+               if ( SCpnt->use_sg ) {
+                       sgList = (struct scatterlist *)SCpnt->request_buffer;
+                       memcpy(&c, sgList[0].address, 0x1);
+               } else {
+                       memcpy(&c, SCpnt->request_buffer, 0x1);
+               }
+#if 0
+               if( (c & 0x1F ) == TYPE_DISK ) {
+                       status = 0xF0;
+               }
+#endif
+               if(IS_RAID_CH(megaCfg, SCpnt->channel) && ((c & 0x1F) == TYPE_DISK)) {
+                       status = 0xF0;
+               }
+       }
+
+
+       /* clear result; otherwise, success returns corrupt value */
+       SCpnt->result = 0;
+
+       if ( 0 && SCpnt->cmnd[0] & M_RD_IOCTL_CMD ) {   /* i.e. ioctl cmd such as M_RD_IOCTL_CMD, M_RD_IOCTL_CMD_NEW of megamgr */
+               switch (status) {
+               case 2:
+               case 0xF0:
+               case 0xF4:
+                       SCpnt->result = (DID_BAD_TARGET << 16) | status;
+                       break;
+               default:
+                       SCpnt->result |= status;
+               }               /*end of switch */
+       } else {
+               /* Convert MegaRAID status to Linux error code */
+               switch (status) {
+               case 0x00:      /* SUCCESS , i.e. SCSI_STATUS_GOOD */
+                       SCpnt->result |= (DID_OK << 16);
+                       break;
+
+               case 0x02:      /* ERROR_ABORTED, i.e. SCSI_STATUS_CHECK_CONDITION */
+
+                       /*set sense_buffer and result fields */
+                       if (mbox->cmd == MEGA_MBOXCMD_PASSTHRU || mbox->cmd ==
+                                                       MEGA_MBOXCMD_PASSTHRU64 ) {
+
+                               memcpy (SCpnt->sense_buffer, pthru->reqsensearea, 14);
+
+                               SCpnt->result = (DRIVER_SENSE << 24) | (DID_OK << 16) |
+                                               (CHECK_CONDITION << 1);
+
+                       } else if (mbox->cmd == MEGA_MBOXCMD_EXTPASSTHRU) {
+
+                               memcpy( SCpnt->sense_buffer, epthru->reqsensearea, 14);
+
+                               SCpnt->result = (DRIVER_SENSE << 24) | (DID_OK << 16) |
+                                               (CHECK_CONDITION << 1);
+
+                       } else {
+                               SCpnt->sense_buffer[0] = 0x70;
+                               SCpnt->sense_buffer[2] = ABORTED_COMMAND;
+                               SCpnt->result |= (CHECK_CONDITION << 1);
+                       }
+                       break;
+
+               case 0x08:      /* ERR_DEST_DRIVE_FAILED, i.e. SCSI_STATUS_BUSY */
+                       SCpnt->result |= (DID_BUS_BUSY << 16) | status;
+                       break;
+
+               default:
+                       SCpnt->result |= (DID_BAD_TARGET << 16) | status;
+                       break;
+               }
+       }
+
+       /* Add Scsi_Command to end of completed queue */
+       if (megaCfg->qCompletedH == NULL) {
+               megaCfg->qCompletedH = megaCfg->qCompletedT = SCpnt;
+       } else {
+               megaCfg->qCompletedT->host_scribble = (unsigned char *) SCpnt;
+               megaCfg->qCompletedT = SCpnt;
+       }
+
+       megaCfg->qCompletedT->host_scribble = (unsigned char *) NULL;
+       megaCfg->qCcnt++;
+}
+
+/*-------------------------------------------------------------------
+ *
+ *                 Build a SCB from a Scsi_Cmnd
+ *
+ * Returns a SCB pointer, or NULL
+ * If NULL is returned, the scsi_done function MUST have been called
+ *
+ *-------------------------------------------------------------------*/
+
+static mega_scb *mega_build_cmd (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt)
+{
+       mega_scb *pScb;
+       mega_mailbox *mbox;
+       mega_passthru *pthru;
+       mega_ext_passthru *epthru;
+       long seg;
+       char islogical;
+       int             max_ldrv_num;
+       int             channel = 0;
+       int             target = 0;
+       int             ldrv_num = 0;   /* logical drive number */
+
+       if ((SCpnt->cmnd[0] == MEGADEVIOC))
+               return megadev_doioctl (megaCfg, SCpnt);
+
+       if ((SCpnt->cmnd[0] == M_RD_IOCTL_CMD)
+                   || (SCpnt->cmnd[0] == M_RD_IOCTL_CMD_NEW))
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)  
+               return mega_ioctl (megaCfg, SCpnt);     /* Handle IOCTL command */
+#else
+       {
+               printk(KERN_WARNING "megaraid ioctl: older interface - "
+                               "not supported.\n");
+               return NULL;
+       }
+#endif
+
+#if 0
+       islogical = ( (SCpnt->channel >= megaCfg->productInfo.SCSIChanPresent) &&
+                                       (SCpnt->channel <= megaCfg->host->max_channel) );
+#endif
+#if 0
+       islogical = (IS_RAID_CH(SCpnt->channel) && /* virtual ch is raid - AM */
+                                               (SCpnt->channel == megaCfg->host->max_channel));
+#endif
+
+       /*
+        * We know on what channels are our logical drives - mega_findCard()
+        */
+       islogical = megaCfg->logdrv_chan[SCpnt->channel];
+
+       /*
+        * The theory: If physical drive is chosen for boot, all the physical
+        * devices are exported before the logical drives, otherwise physical
+        * devices are pushed after logical drives, in which case - Kernel sees
+        * the physical devices on virtual channel which is obviously converted
+        * to actual channel on the HBA.
+        */
+       if( megaCfg->boot_pdrv_enabled ) {
+               if( islogical ) {
+                       /* logical channel */
+                       channel = SCpnt->channel - megaCfg->productInfo.SCSIChanPresent;
+               }
+               else {
+                       channel = SCpnt->channel; /* this is physical channel */
+                       target = SCpnt->target;
+
+                       /*
+                        * boot from a physical disk, that disk needs to be exposed first
+                        * IF both the channels are SCSI, then booting from the second
+                        * channel is not allowed.
+                        */
+                       if( target == 0 ) {
+                               target = megaCfg->boot_pdrv_tgt;
+                       }
+                       else if( target == megaCfg->boot_pdrv_tgt ) {
+                               target = 0;
+                       }
+               }
+       }
+       else {
+               if( islogical ) {
+                       channel = SCpnt->channel; /* this is the logical channel */
+               }
+               else {
+                       channel = SCpnt->channel - NVIRT_CHAN;  /* physical channel */
+                       target = SCpnt->target;
+               }
+       }
+
+       if ( ! megaCfg->support_ext_cdb ) {
+               if (!islogical && SCpnt->lun != 0) {
+                       SCpnt->result = (DID_BAD_TARGET << 16);
+                       callDone (SCpnt);
+                       return NULL;
+               }
+       }
+
+       if (!islogical && SCpnt->target == skip_id) {
+               SCpnt->result = (DID_BAD_TARGET << 16);
+               callDone (SCpnt);
+               return NULL;
+       }
+
+       if (islogical) {
+
+               /* have just LUN 0 for each target on virtual channels */
+               if( SCpnt->lun != 0 ) {
+                       SCpnt->result = (DID_BAD_TARGET << 16);
+                       callDone (SCpnt);
+                       return NULL;
+               }
+
+               ldrv_num = mega_get_ldrv_num(megaCfg, SCpnt, channel);
+
+           max_ldrv_num = (megaCfg->flag & BOARD_40LD) ?
+                                               FC_MAX_LOGICAL_DRIVES : MAX_LOGICAL_DRIVES;
+
+                /*
+                 * max_ldrv_num increases by 0x80 if some logical drive was deleted.
+                 */
+               if(megaCfg->read_ldidmap) {
+                       max_ldrv_num += 0x80;
+               }
+
+               if( ldrv_num > max_ldrv_num ) {
+                       SCpnt->result = (DID_BAD_TARGET << 16);
+                       callDone (SCpnt);
+                       return NULL;
+               }
+
+       } else {
+               if ( SCpnt->lun > 7) {
+                               /* Do not support lun >7 for physically accessed devices */
+                       SCpnt->result = (DID_BAD_TARGET << 16);
+                       callDone (SCpnt);
+                       return NULL;
+               }
+       }
+       /*-----------------------------------------------------
+        *
+        *               Logical drive commands
+        *
+        *-----------------------------------------------------*/
+       if (islogical) {
+               switch (SCpnt->cmnd[0]) {
+               case TEST_UNIT_READY:
+                       memset (SCpnt->request_buffer, 0, SCpnt->request_bufflen);
+                       SCpnt->result = (DID_OK << 16);
+                       callDone (SCpnt);
+                       return NULL;
+
+               case MODE_SENSE:
+                       memset (SCpnt->request_buffer, 0, SCpnt->cmnd[4]);
+                       SCpnt->result = (DID_OK << 16);
+                       callDone (SCpnt);
+                       return NULL;
+
+               case READ_CAPACITY:
+               case INQUIRY:
+                       if(!(megaCfg->flag & (1L << SCpnt->channel))) {
+                               printk(KERN_NOTICE
+                                       "scsi%d: scanning virtual channel %d for logical drives.\n",
+                                       megaCfg->host->host_no, channel);
+
+                               megaCfg->flag |= (1L << SCpnt->channel);
+                       }
+
+                       /* Allocate a SCB and initialize passthru */
+                       if ((pScb = mega_allocateSCB (megaCfg, SCpnt)) == NULL) {
+                               SCpnt->result = (DID_ERROR << 16);
+                               callDone (SCpnt);
+                               return NULL;
+                       }
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+                       pthru = pScb->pthru;
+#else
+                       pthru = &pScb->pthru;
+#endif
+
+                       mbox = (mega_mailbox *) & pScb->mboxData;
+                       memset (mbox, 0, sizeof (pScb->mboxData));
+                       memset (pthru, 0, sizeof (mega_passthru));
+                       pthru->timeout = 0;
+                       pthru->ars = 1;
+                       pthru->reqsenselen = 14;
+                       pthru->islogical = 1;
+                       pthru->logdrv = ldrv_num;
+                       pthru->cdblen = SCpnt->cmd_len;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+                       /*Not sure about the direction */
+                       pScb->dma_direction = PCI_DMA_BIDIRECTIONAL;
+                       pScb->dma_type = M_RD_PTHRU_WITH_BULK_DATA;
+
+#if 0
+/* Normal Code w/o the need for bounce buffer */
+                       pScb->dma_h_bulkdata
+                           = pci_map_single (megaCfg->dev,
+                                             SCpnt->request_buffer,
+                                             SCpnt->request_bufflen,
+                                             pScb->dma_direction);
+
+                       pthru->dataxferaddr = pScb->dma_h_bulkdata;
+#else
+/* Special Code to use bounce buffer for READ_CAPA/INQ */
+                       pthru->dataxferaddr = pScb->dma_bounce_buffer;
+                       pScb->dma_type = M_RD_DMA_TYPE_NONE;
+#endif
+
+#else
+                       pthru->dataxferaddr =
+                           virt_to_bus (SCpnt->request_buffer);
+#endif
+
+                       pthru->dataxferlen = SCpnt->request_bufflen;
+                       memcpy (pthru->cdb, SCpnt->cmnd, SCpnt->cmd_len);
+
+                       /* Initialize mailbox area */
+                       mbox->cmd = MEGA_MBOXCMD_PASSTHRU;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+                       mbox->xferaddr = pScb->dma_passthruhandle64;
+                       TRACE1 (("M_RD_PTHRU_WITH_BULK_DATA Enabled \n"));
+#else
+                       mbox->xferaddr = virt_to_bus (pthru);
+#endif
+                       return pScb;
+
+               case READ_6:
+               case WRITE_6:
+               case READ_10:
+               case WRITE_10:
+                       /* Allocate a SCB and initialize mailbox */
+                       if ((pScb = mega_allocateSCB (megaCfg, SCpnt)) == NULL) {
+                               SCpnt->result = (DID_ERROR << 16);
+                               callDone (SCpnt);
+                               return NULL;
+                       }
+                       mbox = (mega_mailbox *) & pScb->mboxData;
+
+                       memset (mbox, 0, sizeof (pScb->mboxData));
+                       mbox->logdrv = ldrv_num;
+
+                       if (megaCfg->flag & BOARD_64BIT) {
+                               mbox->cmd = (*SCpnt->cmnd == READ_6
+                                            || *SCpnt->cmnd ==
+                                            READ_10) ? MEGA_MBOXCMD_LREAD64 :
+                                   MEGA_MBOXCMD_LWRITE64;
+                       } else {
+                               mbox->cmd = (*SCpnt->cmnd == READ_6
+                                            || *SCpnt->cmnd ==
+                                            READ_10) ? MEGA_MBOXCMD_LREAD :
+                                   MEGA_MBOXCMD_LWRITE;
+                       }
+
+                       /* 6-byte */
+                       if (*SCpnt->cmnd == READ_6 || *SCpnt->cmnd == WRITE_6) {
+                               mbox->numsectors = (u32) SCpnt->cmnd[4];
+                               mbox->lba =
+                                   ((u32) SCpnt->cmnd[1] << 16) |
+                                   ((u32) SCpnt->cmnd[2] << 8) |
+                                   (u32) SCpnt->cmnd[3];
+                               mbox->lba &= 0x1FFFFF;
+
+                               if (*SCpnt->cmnd == READ_6) {
+                                       megaCfg->nReads[(int)ldrv_num]++;
+                                       megaCfg->nReadBlocks[(int)ldrv_num] +=
+                                           mbox->numsectors;
+                               } else {
+                                       megaCfg->nWrites[(int)ldrv_num]++;
+                                       megaCfg->nWriteBlocks[(int)ldrv_num] +=
+                                           mbox->numsectors;
+                               }
+                       }
+
+                       /* 10-byte */
+                       if (*SCpnt->cmnd == READ_10 || *SCpnt->cmnd == WRITE_10) {
+                               mbox->numsectors =
+                                   (u32) SCpnt->cmnd[8] |
+                                   ((u32) SCpnt->cmnd[7] << 8);
+                               mbox->lba =
+                                   ((u32) SCpnt->cmnd[2] << 24) |
+                                   ((u32) SCpnt->cmnd[3] << 16) |
+                                   ((u32) SCpnt->cmnd[4] << 8) |
+                                   (u32) SCpnt->cmnd[5];
+
+                               if (*SCpnt->cmnd == READ_10) {
+                                       megaCfg->nReads[(int)ldrv_num]++;
+                                       megaCfg->nReadBlocks[(int)ldrv_num] +=
+                                           mbox->numsectors;
+                               } else {
+                                       megaCfg->nWrites[(int)ldrv_num]++;
+                                       megaCfg->nWriteBlocks[(int)ldrv_num] +=
+                                           mbox->numsectors;
+                               }
+                       }
+
+                       /* 12-byte */
+                       if (*SCpnt->cmnd == READ_12 || *SCpnt->cmnd == WRITE_12) {
+                               mbox->lba =
+                                   ((u32) SCpnt->cmnd[2] << 24) |
+                                   ((u32) SCpnt->cmnd[3] << 16) |
+                                   ((u32) SCpnt->cmnd[4] << 8) |
+                                   (u32) SCpnt->cmnd[5];
+
+                               mbox->numsectors =
+                                   ((u32) SCpnt->cmnd[6] << 24) |
+                                   ((u32) SCpnt->cmnd[7] << 16) |
+                                   ((u32) SCpnt->cmnd[8] << 8) |
+                                   (u32) SCpnt->cmnd[9];
+
+                               if (*SCpnt->cmnd == READ_12) {
+                                       megaCfg->nReads[(int)ldrv_num]++;
+                                       megaCfg->nReadBlocks[(int)ldrv_num] +=
+                                           mbox->numsectors;
+                               } else {
+                                       megaCfg->nWrites[(int)ldrv_num]++;
+                                       megaCfg->nWriteBlocks[(int)ldrv_num] +=
+                                           mbox->numsectors;
+                               }
+                       }
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+                       if (*SCpnt->cmnd == READ_6 || *SCpnt->cmnd == READ_10
+                                       || *SCpnt->cmnd == READ_12) {
+                               pScb->dma_direction = PCI_DMA_FROMDEVICE;
+                       } else {        /*WRITE_6 or WRITE_10 */
+                               pScb->dma_direction = PCI_DMA_TODEVICE;
+                       }
+#endif
+
+                       /* Calculate Scatter-Gather info */
+                       mbox->numsgelements = mega_build_sglist (megaCfg, pScb,
+                                                                (u32 *)&mbox->xferaddr, (u32 *)&seg);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+                       pScb->iDataSize = seg;
+
+                       if (mbox->numsgelements) {
+                               pScb->dma_type = M_RD_SGLIST_ONLY;
+                               TRACE1 (("M_RD_SGLIST_ONLY Enabled \n"));
+                       } else {
+                               pScb->dma_type = M_RD_BULK_DATA_ONLY;
+                               TRACE1 (("M_RD_BULK_DATA_ONLY Enabled \n"));
+                       }
+#endif
+
+                       return pScb;
+               default:
+                       SCpnt->result = (DID_BAD_TARGET << 16);
+                       callDone (SCpnt);
+                       return NULL;
+               }
+       }
+       /*-----------------------------------------------------
+        *
+        *               Passthru drive commands
+        *
+        *-----------------------------------------------------*/
+       else {
+               /* Allocate a SCB and initialize passthru */
+               if ((pScb = mega_allocateSCB (megaCfg, SCpnt)) == NULL) {
+                       SCpnt->result = (DID_ERROR << 16);
+                       callDone (SCpnt);
+                       return NULL;
+               }
+
+               mbox = (mega_mailbox *) pScb->mboxData;
+               memset (mbox, 0, sizeof (pScb->mboxData));
+
+               if ( megaCfg->support_ext_cdb && SCpnt->cmd_len > 10 ) {
+                       epthru = mega_prepare_extpassthru(megaCfg, pScb, SCpnt, channel,
+                                       target);
+                       mbox->cmd = MEGA_MBOXCMD_EXTPASSTHRU;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+                       mbox->xferaddr = pScb->dma_ext_passthruhandle64;
+
+                       if(epthru->numsgelements) {
+                               pScb->dma_type = M_RD_PTHRU_WITH_SGLIST;
+                       } else {
+                               pScb->dma_type = M_RD_EPTHRU_WITH_BULK_DATA;
+                       }
+#else
+                       mbox->xferaddr = virt_to_bus(epthru);
+#endif
+               }
+               else {
+                       pthru = mega_prepare_passthru(megaCfg, pScb, SCpnt, channel,
+                                       target);
+
+                       /* Initialize mailbox */
+                       mbox->cmd = MEGA_MBOXCMD_PASSTHRU;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+                       mbox->xferaddr = pScb->dma_passthruhandle64;
+
+                       if (pthru->numsgelements) {
+                               pScb->dma_type = M_RD_PTHRU_WITH_SGLIST;
+                       } else {
+                               pScb->dma_type = M_RD_PTHRU_WITH_BULK_DATA;
+                       }
+#else
+                       mbox->xferaddr = virt_to_bus(pthru);
+#endif
+               }
+               return pScb;
+       }
+       return NULL;
+}
+
+static int
+mega_get_ldrv_num(mega_host_config *this_hba, Scsi_Cmnd *sc, int channel)
+{
+       int             tgt;
+       int             ldrv_num;
+
+       tgt = sc->target;
+       
+       if ( tgt > 7 ) tgt--;   /* we do not get inquires for tgt 7 */
+
+       ldrv_num = (channel * 15) + tgt; /* 14 targets per channel */
+
+       /*
+        * If we have a logical drive with boot enabled, project it first
+        */
+       if( this_hba->boot_ldrv_enabled ) {
+               if( ldrv_num == 0 ) {
+                       ldrv_num = this_hba->boot_ldrv;
+               }
+               else {
+                       if( ldrv_num <= this_hba->boot_ldrv ) {
+                               ldrv_num--;
+                       }
+               }
+       }
+
+       /*
+        * If "delete logical drive" feature is enabled on this controller.
+        * Do only if at least one delete logical drive operation was done.
+        *
+        * Also, after logical drive deletion, instead of logical drive number,
+        * the value returned should be 0x80+logical drive id.
+        *
+        * These is valid only for IO commands.
+        */
+
+        if( this_hba->support_random_del && this_hba->read_ldidmap ) {
+               switch(sc->cmnd[0]) {
+               case READ_6:    /* fall through */
+               case WRITE_6:   /* fall through */
+               case READ_10:   /* fall through */
+               case WRITE_10:
+                       ldrv_num += 0x80;
+               }
+        }
+
+        return ldrv_num;
+}
+
+
+static mega_passthru *
+mega_prepare_passthru(mega_host_config *megacfg, mega_scb *scb, Scsi_Cmnd *sc,
+               int channel, int target)
+{
+       mega_passthru *pthru;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+       pthru = scb->pthru;
+#else
+       pthru = &scb->pthru;
+#endif
+       memset (pthru, 0, sizeof (mega_passthru));
+
+       /* set adapter timeout value to 10 min. for tape drive  */
+       /* 0=6sec/1=60sec/2=10min/3=3hrs                        */
+       pthru->timeout = 2;
+       pthru->ars = 1;
+       pthru->reqsenselen = 14;
+       pthru->islogical = 0;
+       pthru->channel = (megacfg->flag & BOARD_40LD) ? 0 : channel;
+       pthru->target = (megacfg->flag & BOARD_40LD) ?
+           (channel << 4) | target : target;
+       pthru->cdblen = sc->cmd_len;
+       pthru->logdrv = sc->lun;
+
+       memcpy (pthru->cdb, sc->cmnd, sc->cmd_len);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+       /* Not sure about the direction */
+       scb->dma_direction = PCI_DMA_BIDIRECTIONAL;
+
+       /* Special Code for Handling READ_CAPA/ INQ using bounce buffers */
+       switch (sc->cmnd[0]) {
+       case INQUIRY:
+       case READ_CAPACITY:
+
+               if(!(megacfg->flag & (1L << sc->channel))) {
+                       printk(KERN_NOTICE
+                               "scsi%d: scanning physical channel %d for devices.\n",
+                               megacfg->host->host_no, channel);
+
+                       megacfg->flag |= (1L << sc->channel);
+               }
+
+               pthru->numsgelements = 0;
+               pthru->dataxferaddr = scb->dma_bounce_buffer;
+               pthru->dataxferlen = sc->request_bufflen;
+               break;
+       default:
+               pthru->numsgelements =
+                       mega_build_sglist(
+                               megacfg, scb, (u32 *)&pthru->dataxferaddr,
+                               (u32 *)&pthru->dataxferlen
+                       );
+               break;
+       }
+#else
+       pthru->numsgelements =
+               mega_build_sglist(
+                       megacfg, scb, (u32 *)&pthru->dataxferaddr,
+                       (u32 *)&pthru->dataxferlen
+               );
+#endif
+       return pthru;
+}
+
+static mega_ext_passthru *
+mega_prepare_extpassthru(mega_host_config *megacfg, mega_scb *scb,
+               Scsi_Cmnd *sc, int channel, int target)
+{
+       mega_ext_passthru *epthru;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+       epthru = scb->epthru;
+#else
+       epthru = &scb->epthru;
+#endif
+       memset(epthru, 0, sizeof(mega_ext_passthru));
+
+       /* set adapter timeout value to 10 min. for tape drive  */
+       /* 0=6sec/1=60sec/2=10min/3=3hrs                        */
+       epthru->timeout = 2;
+       epthru->ars = 1;
+       epthru->reqsenselen = 14;
+       epthru->islogical = 0;
+       epthru->channel = (megacfg->flag & BOARD_40LD) ? 0 : channel;
+       epthru->target = (megacfg->flag & BOARD_40LD) ?
+           (channel << 4) | target : target;
+       epthru->cdblen = sc->cmd_len;
+       epthru->logdrv = sc->lun;
+
+       memcpy(epthru->cdb, sc->cmnd, sc->cmd_len);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+       /* Not sure about the direction */
+       scb->dma_direction = PCI_DMA_BIDIRECTIONAL;
+
+       /* Special Code for Handling READ_CAPA/ INQ using bounce buffers */
+       switch (sc->cmnd[0]) {
+       case INQUIRY:
+       case READ_CAPACITY:
+               if(!(megacfg->flag & (1L << sc->channel))) {
+                       printk(KERN_NOTICE
+                               "scsi%d: scanning physical channel %d for devices.\n",
+                               megacfg->host->host_no, channel);
+
+                       megacfg->flag |= (1L << sc->channel);
+               }
+
+               epthru->numsgelements = 0;
+               epthru->dataxferaddr = scb->dma_bounce_buffer;
+               epthru->dataxferlen = sc->request_bufflen;
+               break;
+       default:
+               epthru->numsgelements =
+                       mega_build_sglist(
+                               megacfg, scb, (u32 *)&epthru->dataxferaddr,
+                               (u32 *)&epthru->dataxferlen
+                       );
+               break;
+       }
+#else
+       epthru->numsgelements =
+               mega_build_sglist(
+                       megacfg, scb, (u32 *)&epthru->dataxferaddr,
+                       (u32 *)&epthru->dataxferlen
+               );
+#endif
+       return epthru;
+}
+
+/* Handle Driver Level IOCTLs
+ * Return value of 0 indicates this function could not handle , so continue
+ * processing
+*/
+
+static int mega_driver_ioctl (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt)
+{
+       unsigned char *data = (unsigned char *) SCpnt->request_buffer;
+       mega_driver_info driver_info;
+
+       /* If this is not our command dont do anything */
+       if (SCpnt->cmnd[0] != M_RD_DRIVER_IOCTL_INTERFACE)
+               return 0;
+
+       switch (SCpnt->cmnd[1]) {
+       case GET_DRIVER_INFO:
+               if (SCpnt->request_bufflen < sizeof (driver_info)) {
+                       SCpnt->result = DID_BAD_TARGET << 16;
+                       callDone (SCpnt);
+                       return 1;
+               }
+
+               driver_info.size = sizeof (driver_info) - sizeof (int);
+               driver_info.version = MEGARAID_IOCTL_VERSION;
+               memcpy (data, &driver_info, sizeof (driver_info));
+               break;
+       default:
+               SCpnt->result = DID_BAD_TARGET << 16;
+       }
+
+       callDone (SCpnt);
+       return 1;
+}
+
+static void inline set_mbox_xfer_addr (mega_host_config * megaCfg, mega_scb * pScb,
+                   mega_ioctl_mbox * mbox, u32 direction)
+{
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+       switch (direction) {
+       case TO_DEVICE:
+               pScb->dma_direction = PCI_DMA_TODEVICE;
+               break;
+       case FROM_DEVICE:
+               pScb->dma_direction = PCI_DMA_FROMDEVICE;
+               break;
+       case FROMTO_DEVICE:
+               pScb->dma_direction = PCI_DMA_BIDIRECTIONAL;
+               break;
+       }
+
+       pScb->dma_h_bulkdata
+           = pci_map_single (megaCfg->dev,
+                             pScb->buff_ptr,
+                             pScb->iDataSize, pScb->dma_direction);
+       mbox->xferaddr = pScb->dma_h_bulkdata;
+       pScb->dma_type = M_RD_BULK_DATA_ONLY;
+       TRACE1 (("M_RD_BULK_DATA_ONLY Enabled \n"));
+#else
+       mbox->xferaddr = virt_to_bus (pScb->buff_ptr);
+#endif
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
+
+/*--------------------------------------------------------------------
+ * build RAID commands for controller, passed down through ioctl()
+ *--------------------------------------------------------------------*/
+static mega_scb *mega_ioctl (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt)
+{
+       mega_scb *pScb;
+       mega_ioctl_mbox *mbox;
+       mega_mailbox *mailbox;
+       mega_passthru *pthru;
+       u8 *mboxdata;
+       long seg, i = 0;
+       unsigned char *data = (unsigned char *) SCpnt->request_buffer;
+
+       if ((pScb = mega_allocateSCB (megaCfg, SCpnt)) == NULL) {
+               SCpnt->result = (DID_ERROR << 16);
+               callDone (SCpnt);
+               return NULL;
+       }
+       pthru = &pScb->pthru;
+
+       mboxdata = (u8 *) & pScb->mboxData;
+       mbox = (mega_ioctl_mbox *) & pScb->mboxData;
+       mailbox = (mega_mailbox *) & pScb->mboxData;
+       memset (mailbox, 0, sizeof (pScb->mboxData));
+
+       if (data[0] == 0x03) {  /* passthrough command */
+               unsigned char cdblen = data[2];
+               memset (pthru, 0, sizeof (mega_passthru));
+               pthru->islogical = (data[cdblen + 3] & 0x80) ? 1 : 0;
+               pthru->timeout = data[cdblen + 3] & 0x07;
+               pthru->reqsenselen = 14;
+               pthru->ars = (data[cdblen + 3] & 0x08) ? 1 : 0;
+               pthru->logdrv = data[cdblen + 4];
+               pthru->channel = data[cdblen + 5];
+               pthru->target = data[cdblen + 6];
+               pthru->cdblen = cdblen;
+               memcpy (pthru->cdb, &data[3], cdblen);
+
+               mailbox->cmd = MEGA_MBOXCMD_PASSTHRU;
+
+
+               pthru->numsgelements = mega_build_sglist (megaCfg, pScb,
+                                                         (u32 *) & pthru->
+                                                         dataxferaddr,
+                                                         (u32 *) & pthru->
+                                                         dataxferlen);
+
+               mailbox->xferaddr = virt_to_bus (pthru);
+
+               for (i = 0; i < (SCpnt->request_bufflen - cdblen - 7); i++) {
+                       data[i] = data[i + cdblen + 7];
+               }
+               return pScb;
+       }
+       /* else normal (nonpassthru) command */
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,0,24)        /*0x020024 */
+       /*
+        *usage of the function copy from user is used in case of data more than
+        *4KB.This is used only with adapters which supports more than 8 logical
+        * drives.This feature is disabled on kernels earlier or same as 2.0.36
+        * as the uaccess.h file is not available with those kernels.
+        */
+
+       if (SCpnt->cmnd[0] == M_RD_IOCTL_CMD_NEW) {
+               /* use external data area for large xfers  */
+               /* If cmnd[0] is set to M_RD_IOCTL_CMD_NEW then *
+                *   cmnd[4..7] = external user buffer     *
+                *   cmnd[8..11] = length of buffer        *
+                *                                         */
+       char *user_area = (char *)*((u32*)&SCpnt->cmnd[4]);
+               u32 xfer_size = *((u32 *) & SCpnt->cmnd[8]);
+               switch (data[0]) {
+               case FW_FIRE_WRITE:
+               case FW_FIRE_FLASH:
+                       if ((ulong) user_area & (PAGE_SIZE - 1)) {
+                               printk
+                                   ("megaraid:user address not aligned on 4K boundary.Error.\n");
+                               SCpnt->result = (DID_ERROR << 16);
+                               callDone (SCpnt);
+                               return NULL;
+                       }
+                       break;
+               default:
+                       break;
+               }
+
+               if (!(pScb->buff_ptr = kmalloc (xfer_size, GFP_KERNEL))) {
+                       printk
+                           ("megaraid: Insufficient mem for M_RD_IOCTL_CMD_NEW.\n");
+                       SCpnt->result = (DID_ERROR << 16);
+                       callDone (SCpnt);
+                       return NULL;
+               }
+
+               copy_from_user (pScb->buff_ptr, user_area, xfer_size);
+               pScb->iDataSize = xfer_size;
+
+               switch (data[0]) {
+               case DCMD_FC_CMD:
+                       switch (data[1]) {
+                       case DCMD_FC_READ_NVRAM_CONFIG:
+                       case DCMD_GET_DISK_CONFIG:
+                               {
+                                       if ((ulong) pScb->
+                                           buff_ptr & (PAGE_SIZE - 1)) {
+                                               printk
+                                                   ("megaraid:user address not sufficient Error.\n");
+                                               SCpnt->result =
+                                                   (DID_ERROR << 16);
+                                               callDone (SCpnt);
+                                               return NULL;
+                                       }
+
+                                       /*building SG list */
+                                       mega_build_kernel_sg (pScb->buff_ptr,
+                                                             xfer_size,
+                                                             pScb, mbox);
+                                       break;
+                               }
+                       default:
+                               break;
+                       }       /*switch (data[1]) */
+                       break;
+               }
+
+       }
+#endif
+
+       mbox->cmd = data[0];
+       mbox->channel = data[1];
+       mbox->param = data[2];
+       mbox->pad[0] = data[3];
+       mbox->logdrv = data[4];
+
+       if (SCpnt->cmnd[0] == M_RD_IOCTL_CMD_NEW) {
+               switch (data[0]) {
+               case FW_FIRE_WRITE:
+                       mbox->cmd = FW_FIRE_WRITE;
+                       mbox->channel = data[1];        /* Current Block Number */
+                       set_mbox_xfer_addr (megaCfg, pScb, mbox, TO_DEVICE);
+                       mbox->numsgelements = 0;
+                       break;
+               case FW_FIRE_FLASH:
+                       mbox->cmd = FW_FIRE_FLASH;
+                       mbox->channel = data[1] | 0x80; /* Origin */
+                       set_mbox_xfer_addr (megaCfg, pScb, mbox, TO_DEVICE);
+                       mbox->numsgelements = 0;
+                       break;
+               case DCMD_FC_CMD:
+                       *(mboxdata + 0) = data[0];      /*mailbox byte 0: DCMD_FC_CMD */
+                       *(mboxdata + 2) = data[1];      /*sub command */
+                       switch (data[1]) {
+                       case DCMD_FC_READ_NVRAM_CONFIG:
+                       case DCMD_FC_READ_NVRAM_CONFIG_64:
+                               /* number of elements in SG list */
+                               *(mboxdata + 3) = mbox->numsgelements;
+                               if (megaCfg->flag & BOARD_64BIT)
+                                       *(mboxdata + 2) =
+                                           DCMD_FC_READ_NVRAM_CONFIG_64;
+                               break;
+                       case DCMD_WRITE_CONFIG:
+                       case DCMD_WRITE_CONFIG_64:
+                               if (megaCfg->flag & BOARD_64BIT)
+                                       *(mboxdata + 2) = DCMD_WRITE_CONFIG_64;
+                               set_mbox_xfer_addr (megaCfg, pScb, mbox,
+                                                   TO_DEVICE);
+                               mbox->numsgelements = 0;
+                               break;
+                       case DCMD_GET_DISK_CONFIG:
+                       case DCMD_GET_DISK_CONFIG_64:
+                               if (megaCfg->flag & BOARD_64BIT)
+                                       *(mboxdata + 2) =
+                                           DCMD_GET_DISK_CONFIG_64;
+                               *(mboxdata + 3) = data[2];      /*number of elements in SG list */
+                               /*nr of elements in SG list */
+                               *(mboxdata + 4) = mbox->numsgelements;
+                               break;
+                       case DCMD_DELETE_LOGDRV:
+                       case DCMD_DELETE_DRIVEGROUP:
+                       case NC_SUBOP_ENQUIRY3:
+                               *(mboxdata + 3) = data[2];
+                               set_mbox_xfer_addr (megaCfg, pScb, mbox,
+                                                   FROMTO_DEVICE);
+                               mbox->numsgelements = 0;
+                               break;
+                       case DCMD_CHANGE_LDNO:
+                       case DCMD_CHANGE_LOOPID:
+                               *(mboxdata + 3) = data[2];
+                               *(mboxdata + 4) = data[3];
+                               set_mbox_xfer_addr (megaCfg, pScb, mbox,
+                                                   TO_DEVICE);
+                               mbox->numsgelements = 0;
+                               break;
+                       default:
+                               set_mbox_xfer_addr (megaCfg, pScb, mbox,
+                                                   FROMTO_DEVICE);
+                               mbox->numsgelements = 0;
+                               break;
+                       }       /*switch */
+                       break;
+               default:
+                       set_mbox_xfer_addr (megaCfg, pScb, mbox, FROMTO_DEVICE);
+                       mbox->numsgelements = 0;
+                       break;
+               }
+       } else {
+
+               mbox->numsgelements = mega_build_sglist (megaCfg, pScb,
+                                                        (u32 *) & mbox->
+                                                        xferaddr,
+                                                        (u32 *) & seg);
+
+               /* Handling some of the fw special commands */
+               switch (data[0]) {
+               case 6: /* START_DEV */
+                       mbox->xferaddr = *((u32 *) & data[i + 6]);
+                       break;
+               default:
+                       break;
+               }
+
+               for (i = 0; i < (SCpnt->request_bufflen - 6); i++) {
+                       data[i] = data[i + 6];
+               }
+       }
+
+       return (pScb);
+}
+
+
+static void mega_build_kernel_sg (char *barea, ulong xfersize, mega_scb * pScb, mega_ioctl_mbox * mbox)
+{
+       ulong i, buffer_area, len, end, end_page, x, idx = 0;
+
+       buffer_area = (ulong) barea;
+       i = buffer_area;
+       end = buffer_area + xfersize;
+       end_page = (end) & ~(PAGE_SIZE - 1);
+
+       do {
+               len = PAGE_SIZE - (i % PAGE_SIZE);
+               x = pScb->sgList[idx].address =
+                   virt_to_bus ((volatile void *) i);
+               pScb->sgList[idx].length = len;
+               i += len;
+               idx++;
+       } while (i < end_page);
+
+       if ((end - i) < 0) {
+               printk ("megaraid:Error in user address\n");
+       }
+
+       if (end - i) {
+               pScb->sgList[idx].address = virt_to_bus ((volatile void *) i);
+               pScb->sgList[idx].length = end - i;
+               idx++;
+       }
+       mbox->xferaddr = virt_to_bus (pScb->sgList);
+       mbox->numsgelements = idx;
+}
+#endif
+
+
+#if DEBUG
+static unsigned int cum_time = 0;
+static unsigned int cum_time_cnt = 0;
+
+static void showMbox (mega_scb * pScb)
+{
+       mega_mailbox *mbox;
+
+       if (pScb == NULL)
+               return;
+
+       mbox = (mega_mailbox *) pScb->mboxData;
+       printk ("%u cmd:%x id:%x #scts:%x lba:%x addr:%x logdrv:%x #sg:%x\n",
+               pScb->SCpnt->pid,
+               mbox->cmd, mbox->cmdid, mbox->numsectors,
+               mbox->lba, mbox->xferaddr, mbox->logdrv, mbox->numsgelements);
+}
+
+#endif
+
+/*--------------------------------------------------------------------
+ * Interrupt service routine
+ *--------------------------------------------------------------------*/
+static void megaraid_isr (int irq, void *devp, struct pt_regs *regs)
+{
+       IO_LOCK_T;
+       mega_host_config * megaCfg;
+       u_char byte, idx, sIdx, tmpBox[MAILBOX_SIZE];
+       u32 dword = 0;
+       mega_mailbox *mbox;
+       mega_scb *pScb;
+       u_char qCnt, qStatus;
+       u_char completed[MAX_FIRMWARE_STATUS];
+       Scsi_Cmnd *SCpnt;
+
+       megaCfg = (mega_host_config *) devp;
+       mbox = (mega_mailbox *) tmpBox;
+
+       if (megaCfg->host->irq == irq) {
+               if (megaCfg->flag & IN_ISR) {
+                       TRACE (("ISR called reentrantly!!\n"));
+                       printk ("ISR called reentrantly!!\n");
+               }
+               megaCfg->flag |= IN_ISR;
+
+               if (mega_busyWaitMbox (megaCfg)) {
+                       printk (KERN_WARNING "Error: mailbox busy in isr!\n");
+               }
+
+               /* Check if a valid interrupt is pending */
+               if (megaCfg->flag & BOARD_QUARTZ) {
+                       dword = RDOUTDOOR (megaCfg);
+                       if (dword != 0x10001234) {
+                               /* Spurious interrupt */
+                               megaCfg->flag &= ~IN_ISR;
+                               return;
+                       }
+               } else {
+                       byte = READ_PORT (megaCfg->host->io_port, INTR_PORT);
+                       if ((byte & VALID_INTR_BYTE) == 0) {
+                               /* Spurious interrupt */
+                               megaCfg->flag &= ~IN_ISR;
+                               return;
+                       }
+                       WRITE_PORT (megaCfg->host->io_port, INTR_PORT, byte);
+               }
+
+               for (idx = 0; idx < MAX_FIRMWARE_STATUS; idx++)
+                       completed[idx] = 0;
+
+               IO_LOCK;
+
+               megaCfg->nInterrupts++;
+               qCnt = 0xff;
+               while ((qCnt = megaCfg->mbox->numstatus) == 0xFF) ;
+
+               qStatus = 0xff;
+               while ((qStatus = megaCfg->mbox->status) == 0xFF) ;
+
+               /* Get list of completed requests */
+               for (idx = 0; idx < qCnt; idx++) {
+                       while ((sIdx = megaCfg->mbox->completed[idx]) == 0xFF) {
+                               printk ("p");
+                       }
+                       completed[idx] = sIdx;
+                       sIdx = 0xFF;
+               }
+
+               if (megaCfg->flag & BOARD_QUARTZ) {
+                       WROUTDOOR (megaCfg, dword);
+                       /* Acknowledge interrupt */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+                       /* In this case mbox contains physical address */
+#if 0
+                       WRINDOOR (megaCfg, megaCfg->adjdmahandle64 | 0x2);
+#else
+                       WRINDOOR (megaCfg, 0x2);
+#endif
+
+#else
+
+#if 0
+                       WRINDOOR (megaCfg, virt_to_bus (megaCfg->mbox) | 0x2);
+#else
+                       WRINDOOR (megaCfg, 0x2);
+#endif
+
+#endif
+
+#if 0
+                       while (RDINDOOR (megaCfg) & 0x02) ;
+#endif
+               } else {
+                       CLEAR_INTR (megaCfg->host->io_port);
+               }
+
+#if DEBUG
+               if (qCnt >= MAX_FIRMWARE_STATUS) {
+                       printk ("megaraid_isr: cmplt=%d ", qCnt);
+               }
+#endif
+
+               for (idx = 0; idx < qCnt; idx++) {
+                       sIdx = completed[idx];
+                       if ((sIdx > 0) && (sIdx <= MAX_COMMANDS)) {
+                               pScb = &megaCfg->scbList[sIdx - 1];
+
+                               /* ASSERT(pScb->state == SCB_ISSUED); */
+
+#if DEBUG
+                               if (((jiffies) - pScb->isrcount) > maxCmdTime) {
+                                       maxCmdTime = (jiffies) - pScb->isrcount;
+                                       printk
+                                           ("megaraid_isr : cmd time = %u\n",
+                                            maxCmdTime);
+                               }
+#endif
+                               /*
+                                * Assuming that the scsi command, for which 
+                                * an abort request was received earlier, has 
+                                * completed.
+                                */
+                               if (pScb->state == SCB_ABORTED) {
+                                       SCpnt = pScb->SCpnt;
+                               }
+                               if (pScb->state == SCB_RESET) {
+                                       SCpnt = pScb->SCpnt;
+                                       mega_freeSCB (megaCfg, pScb);
+                                       SCpnt->result = (DID_RESET << 16);
+                                       if (megaCfg->qCompletedH == NULL) {
+                                               megaCfg->qCompletedH =
+                                                   megaCfg->qCompletedT =
+                                                   SCpnt;
+                                       } else {
+                                               megaCfg->qCompletedT->
+                                                   host_scribble =
+                                                   (unsigned char *) SCpnt;
+                                               megaCfg->qCompletedT = SCpnt;
+                                       }
+                                       megaCfg->qCompletedT->host_scribble =
+                                           (unsigned char *) NULL;
+                                       megaCfg->qCcnt++;
+                                       continue;
+                               }
+
+                               /* We don't want the ISR routine to touch M_RD_IOCTL_CMD_NEW commands, so
+                                * don't mark them as complete, instead we pop their semaphore so
+                                * that the queue routine can finish them off
+                                */
+                               if (pScb->SCpnt->cmnd[0] == M_RD_IOCTL_CMD_NEW) {
+                                       /* save the status byte for the queue routine to use */
+                                       pScb->SCpnt->result = qStatus;
+#if XENO_KILLED
+                                       up (&pScb->ioctl_sem);
+#endif
+                               } else {
+                                       /* Mark command as completed */
+                                       mega_cmd_done (megaCfg, pScb, qStatus);
+                               }
+                       } else {
+                               printk
+                                   ("megaraid: wrong cmd id completed from firmware:id=%x\n",
+                                    sIdx);
+                       }
+               }
+
+               mega_rundoneq (megaCfg);
+
+               megaCfg->flag &= ~IN_ISR;
+               /* Loop through any pending requests */
+               mega_runpendq (megaCfg);
+               IO_UNLOCK;
+
+       }
+
+}
+
+/*==================================================*/
+/* Wait until the controller's mailbox is available */
+/*==================================================*/
+
+static int mega_busyWaitMbox (mega_host_config * megaCfg)
+{
+       mega_mailbox *mbox = (mega_mailbox *) megaCfg->mbox;
+       long counter;
+
+       for (counter = 0; counter < 10000; counter++) {
+               if (!mbox->busy) {
+                       return 0;
+               }
+               udelay (100);
+               barrier ();
+       }
+       return -1;              /* give up after 1 second */
+}
+
+/*=====================================================
+ * Post a command to the card
+ *
+ * Arguments:
+ *   mega_host_config *megaCfg - Controller structure
+ *   u_char *mboxData - Mailbox area, 16 bytes
+ *   mega_scb *pScb   - SCB posting (or NULL if N/A)
+ *   int intr         - if 1, interrupt, 0 is blocking
+ * Return Value: (added on 7/26 for 40ld/64bit)
+ *   -1: the command was not actually issued out
+ *   other cases:
+ *     intr==0, return ScsiStatus, i.e. mbox->status
+ *     intr==1, return 0
+ *=====================================================
+ */
+static int megaIssueCmd (mega_host_config * megaCfg, u_char * mboxData, 
+               mega_scb * pScb, int intr)
+{
+       volatile mega_mailbox *mbox = (mega_mailbox *) megaCfg->mbox;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+       volatile mega_mailbox64 *mbox64 = (mega_mailbox64 *) megaCfg->mbox64;
+#endif
+
+       u_char byte;
+
+#ifdef __LP64__
+       u64 phys_mbox;
+#else
+       u32 phys_mbox;
+#endif
+       u8 retval = -1;
+
+       mboxData[0x1] = (pScb ? pScb->idx + 1 : 0xFE);  /* Set cmdid */
+       mboxData[0xF] = 1;      /* Set busy */
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+       /* In this case mbox contains physical address */
+       phys_mbox = megaCfg->adjdmahandle64;
+#else
+       phys_mbox = virt_to_bus (megaCfg->mbox);
+#endif
+
+#if DEBUG
+       ShowMbox (pScb);
+#endif
+
+       /* Wait until mailbox is free */
+       if (mega_busyWaitMbox (megaCfg)) {
+               printk ("Blocked mailbox......!!\n");
+               udelay (1000);
+
+#if DEBUG
+               showMbox (pLastScb);
+#endif
+
+               /* Abort command */
+               if (pScb == NULL) {
+                       TRACE (("NULL pScb in megaIssue\n"));
+                       printk ("NULL pScb in megaIssue\n");
+               }
+               mega_cmd_done (megaCfg, pScb, 0x08);
+               return -1;
+       }
+
+       pLastScb = pScb;
+
+       /* Copy mailbox data into host structure */
+       megaCfg->mbox64->xferSegment_lo = 0;
+       megaCfg->mbox64->xferSegment_hi = 0;
+
+       memcpy ((char *) mbox, mboxData, 16);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+       switch (mboxData[0]) {
+       case MEGA_MBOXCMD_LREAD64:
+       case MEGA_MBOXCMD_LWRITE64:
+               mbox64->xferSegment_lo = mbox->xferaddr;
+               mbox64->xferSegment_hi = 0;
+               mbox->xferaddr = 0xFFFFFFFF;
+               break;
+       }
+#endif
+
+       /* Kick IO */
+       if (intr) {
+               /* Issue interrupt (non-blocking) command */
+               if (megaCfg->flag & BOARD_QUARTZ) {
+                       mbox->mraid_poll = 0;
+                       mbox->mraid_ack = 0;
+
+                       WRINDOOR (megaCfg, phys_mbox | 0x1);
+               } else {
+                       ENABLE_INTR (megaCfg->host->io_port);
+                       ISSUE_COMMAND (megaCfg->host->io_port);
+               }
+               pScb->state = SCB_ISSUED;
+
+               retval = 0;
+       } else {                /* Issue non-ISR (blocking) command */
+               disable_irq (megaCfg->host->irq);
+               if (megaCfg->flag & BOARD_QUARTZ) {
+                       mbox->mraid_poll = 0;
+                       mbox->mraid_ack = 0;
+                       mbox->numstatus = 0xFF;
+                       mbox->status = 0xFF;
+                       WRINDOOR (megaCfg, phys_mbox | 0x1);
+
+                       while (mbox->numstatus == 0xFF) ;
+                       while (mbox->status == 0xFF) ;
+                       while (mbox->mraid_poll != 0x77) ;
+                       mbox->mraid_poll = 0;
+                       mbox->mraid_ack = 0x77;
+
+                       /* while ((cmdDone = RDOUTDOOR (megaCfg)) != 0x10001234);
+                          WROUTDOOR (megaCfg, cmdDone); */
+
+                       if (pScb) {
+                               mega_cmd_done (megaCfg, pScb, mbox->status);
+                       }
+
+                       WRINDOOR (megaCfg, phys_mbox | 0x2);
+                       while (RDINDOOR (megaCfg) & 0x2) ;
+
+               } else {
+                       DISABLE_INTR (megaCfg->host->io_port);
+                       ISSUE_COMMAND (megaCfg->host->io_port);
+
+                       while (!
+                              ((byte =
+                                READ_PORT (megaCfg->host->io_port,
+                                           INTR_PORT)) & INTR_VALID)) ;
+                       WRITE_PORT (megaCfg->host->io_port, INTR_PORT, byte);
+
+                       ENABLE_INTR (megaCfg->host->io_port);
+                       CLEAR_INTR (megaCfg->host->io_port);
+
+                       if (pScb) {
+                               mega_cmd_done (megaCfg, pScb, mbox->status);
+                       } else {
+                               TRACE (("Error: NULL pScb!\n"));
+                       }
+               }
+               enable_irq (megaCfg->host->irq);
+               retval = mbox->status;
+       }
+#if DEBUG
+       while (mega_busyWaitMbox (megaCfg)) {
+               printk(KERN_ERR "Blocked mailbox on exit......!\n");
+               udelay (1000);
+       }
+#endif
+
+       return retval;
+}
+
+/*-------------------------------------------------------------------
+ * Copies data to SGLIST
+ *-------------------------------------------------------------------*/
+/* Note:
+       For 64 bit cards, we need a minimum of one SG element for read/write
+*/
+
+static int
+mega_build_sglist (mega_host_config * megaCfg, mega_scb * scb,
+                  u32 * buffer, u32 * length)
+{
+       struct scatterlist *sgList;
+       int idx;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+       int sgcnt;
+#endif
+
+       mega_mailbox *mbox = NULL;
+
+       mbox = (mega_mailbox *) scb->mboxData;
+       /* Scatter-gather not used */
+       if (scb->SCpnt->use_sg == 0) {
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+               scb->dma_h_bulkdata = pci_map_single (megaCfg->dev,
+                                     scb->SCpnt->request_buffer,
+                                     scb->SCpnt->request_bufflen,
+                                     scb->dma_direction);
+               /* We need to handle special commands like READ64, WRITE64
+                  as they need a minimum of 1 SG irrespective of actually SG
+                */
+               if ((megaCfg->flag & BOARD_64BIT) &&
+                   ((mbox->cmd == MEGA_MBOXCMD_LREAD64) ||
+                    (mbox->cmd == MEGA_MBOXCMD_LWRITE64))) {
+                       scb->sg64List[0].address = scb->dma_h_bulkdata;
+                       scb->sg64List[0].length = scb->SCpnt->request_bufflen;
+                       *buffer = scb->dma_sghandle64;
+                       *length = (u32)scb->SCpnt->request_bufflen;
+                       scb->sglist_count = 1;
+                       return 1;
+               } else {
+                       *buffer = scb->dma_h_bulkdata;
+                       *length = (u32) scb->SCpnt->request_bufflen;
+               }
+#else
+               *buffer = virt_to_bus (scb->SCpnt->request_buffer);
+               *length = (u32) scb->SCpnt->request_bufflen;
+#endif
+               return 0;
+       }
+
+       sgList = (struct scatterlist *) scb->SCpnt->request_buffer;
+#if 0
+       if (scb->SCpnt->use_sg == 1) {
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+               scb->dma_h_bulkdata = pci_map_single (megaCfg->dev,
+                                     sgList[0].address,
+                                     sgList[0].length, scb->dma_direction);
+
+               if ((megaCfg->flag & BOARD_64BIT) &&
+                   ((mbox->cmd == MEGA_MBOXCMD_LREAD64) ||
+                    (mbox->cmd == MEGA_MBOXCMD_LWRITE64))) {
+                       scb->sg64List[0].address = scb->dma_h_bulkdata;
+                       scb->sg64List[0].length = scb->SCpnt->request_bufflen;
+                       *buffer = scb->dma_sghandle64;
+                       *length = 0;
+                       scb->sglist_count = 1;
+                       return 1;
+               } else {
+                       *buffer = scb->dma_h_bulkdata;
+                       *length = (u32) sgList[0].length;
+               }
+#else
+               *buffer = virt_to_bus (sgList[0].address);
+               *length = (u32) sgList[0].length;
+#endif
+
+               return 0;
+       }
+#endif
+       /* Copy Scatter-Gather list info into controller structure */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+       sgcnt = pci_map_sg (megaCfg->dev,
+                           sgList, scb->SCpnt->use_sg, scb->dma_direction);
+
+       /* Determine the validity of the new count  */
+       if (sgcnt == 0)
+               printk ("pci_map_sg returned zero!!! ");
+
+       for (idx = 0; idx < sgcnt; idx++, sgList++) {
+
+               if ((megaCfg->flag & BOARD_64BIT) &&
+                   ((mbox->cmd == MEGA_MBOXCMD_LREAD64) ||
+                    (mbox->cmd == MEGA_MBOXCMD_LWRITE64))) {
+                       scb->sg64List[idx].address = sg_dma_address (sgList);
+                       scb->sg64List[idx].length = sg_dma_len (sgList);
+               } else {
+                       scb->sgList[idx].address = sg_dma_address (sgList);
+                       scb->sgList[idx].length = sg_dma_len (sgList);
+               }
+
+       }
+
+#else
+       for (idx = 0; idx < scb->SCpnt->use_sg; idx++) {
+               scb->sgList[idx].address = virt_to_bus (sgList[idx].address);
+               scb->sgList[idx].length = (u32) sgList[idx].length;
+       }
+#endif
+
+       /* Reset pointer and length fields */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+       *buffer = scb->dma_sghandle64;
+       scb->sglist_count = scb->SCpnt->use_sg;
+#else
+       *buffer = virt_to_bus (scb->sgList);
+#endif
+
+#if 0
+       *length = 0;
+#endif
+       /*
+        * For passthru command, dataxferlen must be set, even for commands with a
+        * sg list
+        */
+       *length = (u32)scb->SCpnt->request_bufflen;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+       /* Return count of SG requests */
+       return sgcnt;
+#else
+       /* Return count of SG requests */
+       return scb->SCpnt->use_sg;
+#endif
+}
+
+/*--------------------------------------------------------------------
+ * Initializes the address of the controller's mailbox register
+ *  The mailbox register is used to issue commands to the card.
+ *  Format of the mailbox area:
+ *   00 01 command
+ *   01 01 command id
+ *   02 02 # of sectors
+ *   04 04 logical bus address
+ *   08 04 physical buffer address
+ *   0C 01 logical drive #
+ *   0D 01 length of scatter/gather list
+ *   0E 01 reserved
+ *   0F 01 mailbox busy
+ *   10 01 numstatus byte
+ *   11 01 status byte
+ *--------------------------------------------------------------------*/
+static int
+mega_register_mailbox (mega_host_config * megaCfg, u32 paddr)
+{
+       /* align on 16-byte boundary */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+       megaCfg->mbox = &megaCfg->mailbox64ptr->mailbox;
+#else
+       megaCfg->mbox = &megaCfg->mailbox64.mailbox;
+#endif
+
+#ifdef __LP64__
+       megaCfg->mbox = (mega_mailbox *) ((((u64) megaCfg->mbox) + 16) & ((u64) (-1) ^ 0x0F));
+       megaCfg->adjdmahandle64 = (megaCfg->dma_handle64 + 16) & ((u64) (-1) ^ 0x0F);
+       megaCfg->mbox64 = (mega_mailbox64 *) ((u_char *) megaCfg->mbox - sizeof (u64));
+       paddr = (paddr + 4 + 16) & ((u64) (-1) ^ 0x0F);
+#else
+       megaCfg->mbox
+           = (mega_mailbox *) ((((u32) megaCfg->mbox) + 16) & 0xFFFFFFF0);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+       megaCfg->adjdmahandle64 = ((megaCfg->dma_handle64 + 16) & 0xFFFFFFF0);
+#endif
+
+       megaCfg->mbox64 = (mega_mailbox64 *) ((u_char *) megaCfg->mbox - 8);
+       paddr = (paddr + 4 + 16) & 0xFFFFFFF0;
+#endif
+
+       /* Register mailbox area with the firmware */
+       if (!(megaCfg->flag & BOARD_QUARTZ)) {
+               WRITE_PORT (megaCfg->host->io_port, MBOX_PORT0, paddr & 0xFF);
+               WRITE_PORT (megaCfg->host->io_port, MBOX_PORT1,
+                           (paddr >> 8) & 0xFF);
+               WRITE_PORT (megaCfg->host->io_port, MBOX_PORT2,
+                           (paddr >> 16) & 0xFF);
+               WRITE_PORT (megaCfg->host->io_port, MBOX_PORT3,
+                           (paddr >> 24) & 0xFF);
+               WRITE_PORT (megaCfg->host->io_port, ENABLE_MBOX_REGION,
+                           ENABLE_MBOX_BYTE);
+
+               CLEAR_INTR (megaCfg->host->io_port);
+               ENABLE_INTR (megaCfg->host->io_port);
+       }
+       return 0;
+}
+
+/*---------------------------------------------------------------------------
+ * mega_Convert8ldTo40ld() -- takes all info in AdapterInquiry structure and
+ * puts it into ProductInfo and Enquiry3 structures for later use
+ *---------------------------------------------------------------------------*/
+static void mega_Convert8ldTo40ld (mega_RAIDINQ * inquiry,
+                      mega_Enquiry3 * enquiry3,
+                      megaRaidProductInfo * productInfo)
+{
+       int i;
+
+       productInfo->MaxConcCmds = inquiry->AdpInfo.MaxConcCmds;
+       enquiry3->rbldRate = inquiry->AdpInfo.RbldRate;
+       productInfo->SCSIChanPresent = inquiry->AdpInfo.ChanPresent;
+
+       for (i = 0; i < 4; i++) {
+               productInfo->FwVer[i] = inquiry->AdpInfo.FwVer[i];
+               productInfo->BiosVer[i] = inquiry->AdpInfo.BiosVer[i];
+       }
+       enquiry3->cacheFlushInterval = inquiry->AdpInfo.CacheFlushInterval;
+       productInfo->DramSize = inquiry->AdpInfo.DramSize;
+
+       enquiry3->numLDrv = inquiry->LogdrvInfo.NumLDrv;
+
+       for (i = 0; i < MAX_LOGICAL_DRIVES; i++) {
+               enquiry3->lDrvSize[i] = inquiry->LogdrvInfo.LDrvSize[i];
+               enquiry3->lDrvProp[i] = inquiry->LogdrvInfo.LDrvProp[i];
+               enquiry3->lDrvState[i]
+                   = inquiry->LogdrvInfo.LDrvState[i];
+       }
+
+       for (i = 0; i < (MAX_PHYSICAL_DRIVES); i++) {
+               enquiry3->pDrvState[i]
+                   = inquiry->PhysdrvInfo.PDrvState[i];
+       }
+}
+
+/*-------------------------------------------------------------------
+ * Issue an adapter info query to the controller
+ *-------------------------------------------------------------------*/
+static int mega_i_query_adapter (mega_host_config * megaCfg)
+{
+       mega_Enquiry3 *enquiry3Pnt;
+       mega_mailbox *mbox;
+       u_char mboxData[16];
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+       dma_addr_t raid_inq_dma_handle = 0, prod_info_dma_handle = 0, enquiry3_dma_handle = 0;
+#endif
+       u8 retval;
+
+       /* Initialize adapter inquiry mailbox */
+
+       mbox = (mega_mailbox *) mboxData;
+
+       memset ((void *) megaCfg->mega_buffer, 0,
+               sizeof (megaCfg->mega_buffer));
+       memset (mbox, 0, 16);
+
+/*
+ * Try to issue Enquiry3 command
+ * if not succeeded, then issue MEGA_MBOXCMD_ADAPTERINQ command and
+ * update enquiry3 structure
+ */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+       enquiry3_dma_handle = pci_map_single (megaCfg->dev,
+                             (void *) megaCfg->mega_buffer,
+                             (2 * 1024L), PCI_DMA_FROMDEVICE);
+
+       mbox->xferaddr = enquiry3_dma_handle;
+#else
+       /*Taken care */
+       mbox->xferaddr = virt_to_bus ((void *) megaCfg->mega_buffer);
+#endif
+
+       /* Initialize mailbox databuffer addr */
+       enquiry3Pnt = (mega_Enquiry3 *) megaCfg->mega_buffer;
+       /* point mega_Enguiry3 to the data buf */
+
+       mboxData[0] = FC_NEW_CONFIG;    /* i.e. mbox->cmd=0xA1 */
+       mboxData[2] = NC_SUBOP_ENQUIRY3;        /* i.e. 0x0F */
+       mboxData[3] = ENQ3_GET_SOLICITED_FULL;  /* i.e. 0x02 */
+
+       /* Issue a blocking command to the card */
+       if ((retval = megaIssueCmd (megaCfg, mboxData, NULL, 0)) != 0) {        /* the adapter does not support 40ld */
+               mega_RAIDINQ adapterInquiryData;
+               mega_RAIDINQ *adapterInquiryPnt = &adapterInquiryData;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+               raid_inq_dma_handle = pci_map_single (megaCfg->dev,
+                                     (void *) adapterInquiryPnt,
+                                     sizeof (mega_RAIDINQ),
+                                     PCI_DMA_FROMDEVICE);
+               mbox->xferaddr = raid_inq_dma_handle;
+#else
+               /*taken care */
+               mbox->xferaddr = virt_to_bus ((void *) adapterInquiryPnt);
+#endif
+
+               mbox->cmd = MEGA_MBOXCMD_ADAPTERINQ;    /*issue old 0x05 command to adapter */
+               /* Issue a blocking command to the card */ ;
+               retval = megaIssueCmd (megaCfg, mboxData, NULL, 0);
+
+               pci_unmap_single (megaCfg->dev,
+                                 raid_inq_dma_handle,
+                                 sizeof (mega_RAIDINQ), PCI_DMA_FROMDEVICE);
+
+               /*update Enquiry3 and ProductInfo structures with mega_RAIDINQ structure*/
+               mega_Convert8ldTo40ld (adapterInquiryPnt,
+                                      enquiry3Pnt,
+                                      (megaRaidProductInfo *) & megaCfg->
+                                      productInfo);
+
+       } else {                /* adapter supports 40ld */
+               megaCfg->flag |= BOARD_40LD;
+
+               pci_unmap_single (megaCfg->dev,
+                                 enquiry3_dma_handle,
+                                 (2 * 1024L), PCI_DMA_FROMDEVICE);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+/*get productInfo, which is static information and will be unchanged*/
+               prod_info_dma_handle
+                   = pci_map_single (megaCfg->dev,
+                                     (void *) &megaCfg->productInfo,
+                                     sizeof (megaRaidProductInfo),
+                                     PCI_DMA_FROMDEVICE);
+               mbox->xferaddr = prod_info_dma_handle;
+#else
+               /*taken care */
+               mbox->xferaddr = virt_to_bus ((void *) &megaCfg->productInfo);
+#endif
+
+               mboxData[0] = FC_NEW_CONFIG;    /* i.e. mbox->cmd=0xA1 */
+               mboxData[2] = NC_SUBOP_PRODUCT_INFO;    /* i.e. 0x0E */
+
+               if ((retval = megaIssueCmd (megaCfg, mboxData, NULL, 0)) != 0)
+                       printk ("megaraid: Product_info cmd failed with error: %d\n",
+                               retval);
+
+               pci_unmap_single (megaCfg->dev,
+                                 prod_info_dma_handle,
+                                 sizeof (megaRaidProductInfo),
+                                 PCI_DMA_FROMDEVICE);
+       }
+
+       /*
+        * kernel scans the channels from 0 to <= max_channel
+        */
+       megaCfg->host->max_channel =
+               megaCfg->productInfo.SCSIChanPresent + NVIRT_CHAN -1;
+
+       megaCfg->host->max_id = 16;     /* max targets per channel */
+
+       megaCfg->host->max_lun = 7;     /* Upto 7 luns for non disk devices */
+
+       megaCfg->host->cmd_per_lun = MAX_CMD_PER_LUN;
+
+       megaCfg->numldrv = enquiry3Pnt->numLDrv;
+       megaCfg->max_cmds = megaCfg->productInfo.MaxConcCmds;
+       if (megaCfg->max_cmds > MAX_COMMANDS)
+               megaCfg->max_cmds = MAX_COMMANDS - 1;
+
+       megaCfg->host->can_queue = megaCfg->max_cmds - 1;
+
+       /* use HP firmware and bios version encoding */
+       if (megaCfg->productInfo.subSystemVendorID == HP_SUBSYS_ID) {
+               sprintf (megaCfg->fwVer, "%c%d%d.%d%d",
+                        megaCfg->productInfo.FwVer[2],
+                        megaCfg->productInfo.FwVer[1] >> 8,
+                        megaCfg->productInfo.FwVer[1] & 0x0f,
+                        megaCfg->productInfo.FwVer[0] >> 8,
+                        megaCfg->productInfo.FwVer[0] & 0x0f);
+               sprintf (megaCfg->biosVer, "%c%d%d.%d%d",
+                        megaCfg->productInfo.BiosVer[2],
+                        megaCfg->productInfo.BiosVer[1] >> 8,
+                        megaCfg->productInfo.BiosVer[1] & 0x0f,
+                        megaCfg->productInfo.BiosVer[0] >> 8,
+                        megaCfg->productInfo.BiosVer[0] & 0x0f);
+       } else {
+               memcpy (megaCfg->fwVer, (char *) megaCfg->productInfo.FwVer, 4);
+               megaCfg->fwVer[4] = 0;
+
+               memcpy (megaCfg->biosVer, (char *) megaCfg->productInfo.BiosVer, 4);
+               megaCfg->biosVer[4] = 0;
+       }
+       megaCfg->support_ext_cdb = mega_support_ext_cdb(megaCfg);
+
+       printk (KERN_NOTICE "megaraid: [%s:%s] detected %d logical drives" M_RD_CRLFSTR,
+               megaCfg->fwVer, megaCfg->biosVer, megaCfg->numldrv);
+
+       if ( megaCfg->support_ext_cdb ) {
+               printk(KERN_NOTICE "megaraid: supports extended CDBs.\n");
+       }
+
+       /*
+        * I hope that I can unmap here, reason DMA transaction is not required any more
+        * after this
+        */
+
+       return 0;
+}
+
+/*-------------------------------------------------------------------------
+ *
+ *                      Driver interface functions
+ *
+ *-------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------
+ * Returns data to be displayed in /proc/scsi/megaraid/X
+ *----------------------------------------------------------*/
+#if XENO_KILLED
+int megaraid_proc_info (char *buffer, char **start, off_t offset,
+                   int length, int host_no, int inout)
+{
+       *start = buffer;
+       return 0;
+}
+#endif
+
+static int mega_findCard (Scsi_Host_Template * pHostTmpl,
+              u16 pciVendor, u16 pciDev, long flag)
+{
+       mega_host_config *megaCfg = NULL;
+       struct Scsi_Host *host = NULL;
+       u_char pciBus, pciDevFun, megaIrq;
+
+       u16 magic;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+       u32 magic64;
+#endif
+
+       int             i, j;
+
+#ifdef __LP64__
+       u64 megaBase;
+#else
+       u32 megaBase;
+#endif
+
+       u16 pciIdx = 0;
+       u16 numFound = 0;
+       u16 subsysid, subsysvid;
+#if 0
+       u8 mega_ch_class;
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0) /* 0x20100 */
+       while (!pcibios_find_device
+              (pciVendor, pciDev, pciIdx, &pciBus, &pciDevFun)) {
+#else
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0) /*0x20300 */
+       struct pci_dev *pdev = NULL;
+#else
+       struct pci_dev *pdev = pci_devices;
+#endif
+
+       while ((pdev = pci_find_device (pciVendor, pciDev, pdev))) {
+               if(pci_enable_device (pdev))
+                       continue;
+               pciBus = pdev->bus->number;
+               pciDevFun = pdev->devfn;
+#endif
+               if ((flag & BOARD_QUARTZ) && (skip_id == -1)) {
+                               if( (pciVendor == PCI_VENDOR_ID_PERC4_DI_YSTONE &&
+                                       pciDev == PCI_DEVICE_ID_PERC4_DI_YSTONE) ||
+                                       (pciVendor == PCI_VENDOR_ID_PERC4_QC_VERDE &&
+                                       pciDev == PCI_DEVICE_ID_PERC4_QC_VERDE) ) {
+
+                                       flag |= BOARD_64BIT;
+                               }
+                               else {
+                                       pcibios_read_config_word (pciBus, pciDevFun,
+                                                                 PCI_CONF_AMISIG, &magic);
+                                       if ((magic != AMI_SIGNATURE)
+                                               && (magic != AMI_SIGNATURE_471)) {
+                                               pciIdx++;
+                                               continue;       /* not an AMI board */
+                                       }
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+                                       pcibios_read_config_dword (pciBus, pciDevFun,
+                                                                  PCI_CONF_AMISIG64, &magic64);
+
+                                       if (magic64 == AMI_64BIT_SIGNATURE)
+                                               flag |= BOARD_64BIT;
+#endif
+                               }
+               }
+
+               /* Hmmm...Should we not make this more modularized so that in future we dont add
+                  for each firmware */
+
+               if (flag & BOARD_QUARTZ) {
+                       /* Check to see if this is a Dell PERC RAID controller model 466 */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0) /* 0x20100 */
+                       pcibios_read_config_word (pciBus, pciDevFun,
+                                                 PCI_SUBSYSTEM_VENDOR_ID,
+                                                 &subsysvid);
+                       pcibios_read_config_word (pciBus, pciDevFun,
+                                                 PCI_SUBSYSTEM_ID, &subsysid);
+#else
+                       pci_read_config_word (pdev,
+                                             PCI_SUBSYSTEM_VENDOR_ID,
+                                             &subsysvid);
+                       pci_read_config_word (pdev,
+                                             PCI_SUBSYSTEM_ID, &subsysid);
+#endif
+
+                       /*
+                        * If we do not find the valid subsys vendor id, refuse to load
+                        * the driver. This is part of PCI200X compliance
+                        */
+                       if( (subsysvid != AMI_SUBSYS_ID) &&
+                                       (subsysvid != DELL_SUBSYS_ID) &&
+                                       (subsysvid != LSI_SUBSYS_ID) &&
+                                       (subsysvid != HP_SUBSYS_ID) ) continue;
+
+               }
+
+               printk (KERN_NOTICE
+                       "megaraid: found 0x%4.04x:0x%4.04x:idx %d:bus %d:slot %d:func %d\n",
+                       pciVendor, pciDev, pciIdx, pciBus, PCI_SLOT (pciDevFun),
+                       PCI_FUNC (pciDevFun));
+               /* Read the base port and IRQ from PCI */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0) /* 0x20100 */
+               pcibios_read_config_dword (pciBus, pciDevFun,
+                                          PCI_BASE_ADDRESS_0,
+                                          (u_int *) & megaBase);
+               pcibios_read_config_byte (pciBus, pciDevFun,
+                                         PCI_INTERRUPT_LINE, &megaIrq);
+#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)       /*0x20300 */
+               megaBase = pdev->base_address[0];
+               megaIrq = pdev->irq;
+#else
+
+               megaBase = pci_resource_start (pdev, 0);
+               megaIrq = pdev->irq;
+#endif
+
+               pciIdx++;
+
+               if (flag & BOARD_QUARTZ) {
+                       megaBase &= PCI_BASE_ADDRESS_MEM_MASK;
+                       megaBase = (long) ioremap (megaBase, 128);
+                       if (!megaBase)
+                               continue;
+               } else {
+                       megaBase &= PCI_BASE_ADDRESS_IO_MASK;
+                       megaBase += 0x10;
+               }
+
+               /* Initialize SCSI Host structure */
+               host = scsi_register (pHostTmpl, sizeof (mega_host_config));
+               if (!host)
+                       goto err_unmap;
+
+               /*
+                * Comment the following initialization if you know 'max_sectors' is
+                * not defined for this kernel.
+                * This field was introduced in Linus's kernel 2.4.7pre3 and it
+                * greatly increases the IO performance - AM
+                */
+               host->max_sectors = 1024;
+
+               scsi_set_pci_device(host, pdev);
+               megaCfg = (mega_host_config *) host->hostdata;
+               memset (megaCfg, 0, sizeof (mega_host_config));
+
+               printk (KERN_NOTICE "scsi%d : Found a MegaRAID controller at 0x%x, IRQ: %d"
+                       M_RD_CRLFSTR, host->host_no, (u_int) megaBase, megaIrq);
+
+               if (flag & BOARD_64BIT)
+                       printk (KERN_NOTICE "scsi%d : Enabling 64 bit support\n",
+                               host->host_no);
+
+               /* Copy resource info into structure */
+               megaCfg->qCompletedH = NULL;
+               megaCfg->qCompletedT = NULL;
+               megaCfg->qPendingH = NULL;
+               megaCfg->qPendingT = NULL;
+               megaCfg->qFreeH = NULL;
+               megaCfg->qFreeT = NULL;
+               megaCfg->qFcnt = 0;
+               megaCfg->qPcnt = 0;
+               megaCfg->qCcnt = 0;
+               megaCfg->lock_free = SPIN_LOCK_UNLOCKED;
+               megaCfg->lock_pend = SPIN_LOCK_UNLOCKED;
+               megaCfg->lock_scsicmd = SPIN_LOCK_UNLOCKED;
+               megaCfg->flag = flag;
+               megaCfg->int_qh = NULL;
+               megaCfg->int_qt = NULL;
+               megaCfg->int_qlen = 0;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+               megaCfg->dev = pdev;
+#endif
+               megaCfg->host = host;
+               megaCfg->base = megaBase;
+               megaCfg->host->irq = megaIrq;
+               megaCfg->host->io_port = megaBase;
+               megaCfg->host->n_io_port = 16;
+               megaCfg->host->unique_id = (pciBus << 8) | pciDevFun;
+               megaCtlrs[numCtlrs] = megaCfg;
+
+               if (!(flag & BOARD_QUARTZ)) {
+
+                       /* Request our IO Range */
+                       if( !request_region(megaBase, 16, "megaraid") )
+                               goto err_unregister;
+               }
+
+               /* Request our IRQ */
+               if (request_irq (megaIrq, megaraid_isr, SA_SHIRQ,
+                                "megaraid", megaCfg)) {
+                       printk (KERN_WARNING
+                               "megaraid: Couldn't register IRQ %d!\n",
+                               megaIrq);
+                       goto err_release;
+               }
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+               /*
+                * unmap while releasing the driver, Is it required to be 
+                * PCI_DMA_BIDIRECTIONAL 
+               */
+
+               megaCfg->mailbox64ptr
+                   = pci_alloc_consistent (megaCfg->dev,
+                                           sizeof (mega_mailbox64),
+                                           &(megaCfg->dma_handle64));
+
+               mega_register_mailbox (megaCfg,
+                                      virt_to_bus ((void *) megaCfg->
+                                                   mailbox64ptr));
+#else
+               mega_register_mailbox (megaCfg,
+                                      virt_to_bus ((void *) &megaCfg->
+                                                   mailbox64));
+#endif
+
+               mega_i_query_adapter (megaCfg);
+
+               if ((subsysid == 0x1111) && (subsysvid == 0x1111)) {
+
+                       /*
+                        * Which firmware
+                        */
+                       if( strcmp(megaCfg->fwVer, "3.00") == 0 ||
+                                       strcmp(megaCfg->fwVer, "3.01") == 0 ) {
+
+                               printk( KERN_WARNING
+                                       "megaraid: Your  card is a Dell PERC 2/SC RAID controller "
+                                       "with  firmware\nmegaraid: 3.00 or 3.01.  This driver is "
+                                       "known to have corruption issues\nmegaraid: with those "
+                                       "firmware versions on this specific card.  In order\n"
+                                       "megaraid: to protect your data, please upgrade your "
+                                       "firmware to version\nmegaraid: 3.10 or later, available "
+                                       "from the Dell Technical Support web\nmegaraid: site at\n"
+                                       "http://support.dell.com/us/en/filelib/download/"
+                                       "index.asp?fileid=2940\n"
+                               );
+                       }
+               }
+
+               /*
+                * If we have a HP 1M(0x60E7)/2M(0x60E8) controller with
+                * firmware H.01.07 or H.01.08, disable 64 bit support,
+                * since this firmware cannot handle 64 bit addressing
+                */
+
+               if( (subsysvid == HP_SUBSYS_ID) &&
+                               ((subsysid == 0x60E7)||(subsysid == 0x60E8)) ) {
+
+                       /*
+                        * which firmware
+                        */
+                       if( strcmp(megaCfg->fwVer, "H01.07") == 0 || 
+                           strcmp(megaCfg->fwVer, "H01.08") == 0 ||
+                           strcmp(megaCfg->fwVer, "H01.09") == 0 )
+                       {
+                               printk(KERN_WARNING
+                                               "megaraid: Firmware H.01.07/8/9 on 1M/2M "
+                                               "controllers\nmegaraid: do not support 64 bit "
+                                               "addressing.\n"
+                                               "megaraid: DISABLING 64 bit support.\n");
+                               megaCfg->flag &= ~BOARD_64BIT;
+                       }
+               }
+
+               if (mega_is_bios_enabled (megaCfg)) {
+                       mega_hbas[numCtlrs].is_bios_enabled = 1;
+               }
+
+               /*
+                * Find out which channel is raid and which is scsi
+                */
+               mega_enum_raid_scsi(megaCfg);
+
+               /*
+                * Find out if a logical drive is set as the boot drive. If there is
+                * one, will make that as the first logical drive.
+                * ROMB: Do we have to boot from a physical drive. Then all the
+                * physical drives would appear before the logical disks. Else, all
+                * the physical drives would be exported to the mid layer after
+                * logical disks.
+                */
+               mega_get_boot_drv(megaCfg);
+
+               if( ! megaCfg->boot_pdrv_enabled ) {
+                       for( i = 0; i < NVIRT_CHAN; i++ )
+                               megaCfg->logdrv_chan[i] = 1;
+
+                       for( i = NVIRT_CHAN; i < MAX_CHANNEL + NVIRT_CHAN; i++ )
+                               megaCfg->logdrv_chan[i] = 0;
+
+                       megaCfg->mega_ch_class <<= NVIRT_CHAN;
+               }
+               else {
+                       j = megaCfg->productInfo.SCSIChanPresent;
+                       for( i = 0; i < j; i++ )
+                               megaCfg->logdrv_chan[i] = 0;
+
+                       for( i = j; i < NVIRT_CHAN + j; i++ )
+                               megaCfg->logdrv_chan[i] = 1;
+               }
+
+
+               mega_hbas[numCtlrs].hostdata_addr = megaCfg;
+
+               /*
+                * Do we support random deletion and addition of logical drives
+                */
+               megaCfg->read_ldidmap = 0;      /* set it after first logdrv delete cmd */
+               megaCfg->support_random_del = mega_support_random_del(megaCfg);
+
+               /* Initialize SCBs */
+               if (mega_init_scb (megaCfg)) {
+                       pci_free_consistent (megaCfg->dev,
+                                            sizeof (mega_mailbox64),
+                                            (void *) megaCfg->mailbox64ptr,
+                                            megaCfg->dma_handle64);
+                       scsi_unregister (host);
+                       continue;
+               }
+
+               /*
+                * Fill in the structure which needs to be passed back to the
+                * application when it does an ioctl() for controller related
+                * information.
+                */
+
+               i = numCtlrs;
+               numCtlrs++;
+
+               mcontroller[i].base = megaBase;
+               mcontroller[i].irq = megaIrq;
+               mcontroller[i].numldrv = megaCfg->numldrv;
+               mcontroller[i].pcibus = pciBus;
+               mcontroller[i].pcidev = pciDev;
+               mcontroller[i].pcifun = PCI_FUNC (pciDevFun);
+               mcontroller[i].pciid = pciIdx;
+               mcontroller[i].pcivendor = pciVendor;
+               mcontroller[i].pcislot = PCI_SLOT (pciDevFun);
+               mcontroller[i].uid = (pciBus << 8) | pciDevFun;
+
+               numFound++;
+
+               /* Set the Mode of addressing to 64 bit */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+               if ((megaCfg->flag & BOARD_64BIT) && BITS_PER_LONG == 64)
+#ifdef __LP64__
+                       pdev->dma_mask = 0xffffffffffffffff;
+#else
+                       pdev->dma_mask = 0xffffffff;
+#endif
+#endif
+               continue;
+             err_release:
+               if (flag & BOARD_QUARTZ)
+                       release_region (megaBase, 16);
+             err_unregister:
+               scsi_unregister (host);
+             err_unmap:
+               if (flag & BOARD_QUARTZ)
+                       iounmap ((void *) megaBase);
+       }
+       return numFound;
+}
+
+/*---------------------------------------------------------
+ * Detects if a megaraid controller exists in this system
+ *---------------------------------------------------------*/
+
+int megaraid_detect (Scsi_Host_Template * pHostTmpl)
+{
+#if XENO_KILLED
+  int ctlridx = 0;
+#endif
+  int count = 0;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) /*0x20300 */
+       pHostTmpl->proc_dir = &proc_scsi_megaraid;
+#else
+       pHostTmpl->proc_name = "megaraid";
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0) /* 0x20100 */
+       if (!pcibios_present ()) {
+               printk (KERN_WARNING "megaraid: PCI bios not present."
+                       M_RD_CRLFSTR);
+               return 0;
+       }
+#endif
+       skip_id = -1;
+       if (megaraid && !strncmp (megaraid, "skip", strlen ("skip"))) {
+               if (megaraid[4] != '\0') {
+                       skip_id = megaraid[4] - '0';
+                       if (megaraid[5] != '\0') {
+                               skip_id = (skip_id * 10) + (megaraid[5] - '0');
+                       }
+               }
+               skip_id = (skip_id > 15) ? -1 : skip_id;
+       }
+
+       printk (KERN_NOTICE "megaraid: " MEGARAID_VERSION);
+
+       memset (mega_hbas, 0, sizeof (mega_hbas));
+
+       /* Detect ROMBs first */
+       count += mega_findCard (pHostTmpl, PCI_VENDOR_ID_DISCOVERY,
+                               PCI_DEVICE_ID_DISCOVERY, BOARD_QUARTZ);
+       count += mega_findCard (pHostTmpl, PCI_VENDOR_ID_PERC4_DI_YSTONE,
+                               PCI_DEVICE_ID_PERC4_DI_YSTONE, BOARD_QUARTZ);
+       /* Then detect cards based on date they were produced, oldest first */
+       count += mega_findCard (pHostTmpl, PCI_VENDOR_ID_AMI,
+                               PCI_DEVICE_ID_AMI_MEGARAID, 0);
+       count += mega_findCard (pHostTmpl, PCI_VENDOR_ID_AMI,
+                               PCI_DEVICE_ID_AMI_MEGARAID2, 0);
+       count += mega_findCard (pHostTmpl, 0x8086,
+                               PCI_DEVICE_ID_AMI_MEGARAID3, BOARD_QUARTZ);
+       count += mega_findCard (pHostTmpl, PCI_VENDOR_ID_AMI,
+                               PCI_DEVICE_ID_AMI_MEGARAID3, BOARD_QUARTZ);
+       count += mega_findCard (pHostTmpl, PCI_VENDOR_ID_LSI_LOGIC,
+                               PCI_DEVICE_ID_AMI_MEGARAID3, BOARD_QUARTZ);
+       count += mega_findCard (pHostTmpl, PCI_VENDOR_ID_PERC4_QC_VERDE,
+                               PCI_DEVICE_ID_PERC4_QC_VERDE, BOARD_QUARTZ);
+
+       mega_reorder_hosts ();
+
+#ifdef CONFIG_PROC_FS
+       if (count) {
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0) /*0x20300 */
+               mega_proc_dir_entry = proc_mkdir ("megaraid", &proc_root);
+#else
+               mega_proc_dir_entry = create_proc_entry ("megaraid",
+                                                        S_IFDIR | S_IRUGO |
+                                                        S_IXUGO, &proc_root);
+#endif
+               if (!mega_proc_dir_entry)
+                       printk ("megaraid: failed to create megaraid root\n");
+               else
+                       for (ctlridx = 0; ctlridx < count; ctlridx++)
+                               mega_create_proc_entry (ctlridx,
+                                                       mega_proc_dir_entry);
+       }
+#endif
+
+       /*
+        * Register the driver as a character device, for applications to access
+        * it for ioctls.
+        * Ideally, this should go in the init_module() routine, but since it is
+        * hidden in the file "scsi_module.c" ( included in the end ), we define
+        * it here
+        * First argument (major) to register_chrdev implies a dynamic major
+        * number allocation.
+        */
+#if XENO_KILLED
+       if (count) {
+               major = register_chrdev (0, "megadev", &megadev_fops);
+
+               /*
+                * Register the Shutdown Notification hook in kernel
+                */
+               if (register_reboot_notifier (&mega_notifier)) {
+                       printk ("MegaRAID Shutdown routine not registered!!\n");
+               }
+
+               init_MUTEX (&mimd_entry_mtx);
+       }
+#endif
+
+       return count;
+}
+
+/*---------------------------------------------------------------------
+ * Release the controller's resources
+ *---------------------------------------------------------------------*/
+int megaraid_release (struct Scsi_Host *pSHost)
+{
+       mega_host_config *megaCfg;
+       mega_mailbox *mbox;
+       u_char mboxData[16];
+#ifdef CONFIG_PROC_FS
+       int i;
+#endif
+
+       megaCfg = (mega_host_config *) pSHost->hostdata;
+       mbox = (mega_mailbox *) mboxData;
+
+       /* Flush cache to disk */
+       memset (mbox, 0, 16);
+       mboxData[0] = 0xA;
+
+       free_irq (megaCfg->host->irq, megaCfg); /* Must be freed first, otherwise
+                                                  extra interrupt is generated */
+
+       /* Issue a blocking (interrupts disabled) command to the card */
+       megaIssueCmd (megaCfg, mboxData, NULL, 0);
+
+       /* Free our resources */
+       if (megaCfg->flag & BOARD_QUARTZ) {
+               iounmap ((void *) megaCfg->base);
+       } else {
+               release_region (megaCfg->host->io_port, 16);
+       }
+
+       mega_freeSgList (megaCfg);
+       pci_free_consistent (megaCfg->dev,
+                            sizeof (mega_mailbox64),
+                            (void *) megaCfg->mailbox64ptr,
+                            megaCfg->dma_handle64);
+
+#ifdef CONFIG_PROC_FS
+       if (megaCfg->controller_proc_dir_entry) {
+               remove_proc_entry ("stat", megaCfg->controller_proc_dir_entry);
+               remove_proc_entry ("status",
+                                  megaCfg->controller_proc_dir_entry);
+               remove_proc_entry ("config",
+                                  megaCfg->controller_proc_dir_entry);
+               remove_proc_entry ("mailbox",
+                                  megaCfg->controller_proc_dir_entry);
+               for (i = 0; i < numCtlrs; i++) {
+                       char buf[12] = { 0 };
+                       sprintf (buf, "%d", i);
+                       remove_proc_entry (buf, mega_proc_dir_entry);
+               }
+               remove_proc_entry ("megaraid", &proc_root);
+       }
+#endif
+
+       /*
+        *      Release the controller memory. A word of warning this frees
+        *      hostdata and that includes megaCfg-> so be careful what you
+        *      dereference beyond this point
+        */
+        
+       scsi_unregister (pSHost);
+
+       /*
+        * Unregister the character device interface to the driver. Ideally this
+        * should have been done in cleanup_module routine. Since this is hidden
+        * in file "scsi_module.c", we do it here.
+        * major is the major number of the character device returned by call to
+        * register_chrdev() routine.
+        */
+
+#if XENO_KILLED
+       unregister_chrdev (major, "megadev");
+       unregister_reboot_notifier (&mega_notifier);
+#endif
+
+       return 0;
+}
+
+static int mega_is_bios_enabled (mega_host_config * megacfg)
+{
+       mega_mailbox *mboxpnt;
+       unsigned char mbox[16];
+       int ret;
+
+       mboxpnt = (mega_mailbox *) mbox;
+
+       memset (mbox, 0, sizeof (mbox));
+       memset ((void *) megacfg->mega_buffer,
+               0, sizeof (megacfg->mega_buffer));
+
+       /*
+        * issue command to find out if the BIOS is enabled for this controller
+        */
+       mbox[0] = IS_BIOS_ENABLED;
+       mbox[2] = GET_BIOS;
+
+       mboxpnt->xferaddr = virt_to_bus ((void *) megacfg->mega_buffer);
+
+       ret = megaIssueCmd (megacfg, mbox, NULL, 0);
+
+       return (*(char *) megacfg->mega_buffer);
+}
+
+/*
+ * Find out what channels are RAID/SCSI
+ */
+static void
+mega_enum_raid_scsi(mega_host_config *megacfg)
+{
+       mega_mailbox *mboxp;
+       unsigned char mbox[16];
+       int             i;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+       dma_addr_t      dma_handle;
+#endif
+
+       mboxp = (mega_mailbox *)mbox;
+
+       memset(mbox, 0, sizeof(mbox));
+       /*
+        * issue command to find out what channels are raid/scsi
+        */
+       mbox[0] = CHNL_CLASS;
+       mbox[2] = GET_CHNL_CLASS;
+
+       memset((void *)megacfg->mega_buffer, 0, sizeof(megacfg->mega_buffer));
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+       dma_handle = pci_map_single(megacfg->dev, (void *)megacfg->mega_buffer,
+                             (2 * 1024L), PCI_DMA_FROMDEVICE);
+
+       mboxp->xferaddr = dma_handle;
+#else
+       mboxp->xferaddr = virt_to_bus((void *)megacfg->mega_buffer);
+#endif
+
+       /*
+        * Non-ROMB firware fail this command, so all channels
+        * must be shown RAID
+        */
+       megacfg->mega_ch_class = 0xFF;
+       if( megaIssueCmd(megacfg, mbox, NULL, 0) == 0 ) {
+               megacfg->mega_ch_class = *((char *)megacfg->mega_buffer);
+       }
+
+       for( i = 0; i < megacfg->productInfo.SCSIChanPresent; i++ ) {
+               if( (megacfg->mega_ch_class >> i) & 0x01 )
+                       printk(KERN_NOTICE"megaraid: channel[%d] is raid.\n", i+1);
+               else
+                       printk(KERN_NOTICE"megaraid: channel[%d] is scsi.\n", i+1);
+       }
+
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+       pci_unmap_single(megacfg->dev, dma_handle,
+                                 (2 * 1024L), PCI_DMA_FROMDEVICE);
+#endif
+
+}
+
+
+/*
+ * get the boot logical drive number if enabled
+ */
+void
+mega_get_boot_drv(mega_host_config *megacfg)
+{
+       mega_mailbox *mboxp;
+       unsigned char mbox[16];
+       struct private_bios_data *prv_bios_data;
+       u16             cksum = 0;
+       u8              *cksum_p;
+       u8              boot_pdrv;
+       int             i;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+       dma_addr_t      dma_handle;
+#endif
+
+       mboxp = (mega_mailbox *)mbox;
+
+       memset(mbox, 0, sizeof(mbox));
+
+       mbox[0] = BIOS_PVT_DATA;
+       mbox[2] = GET_BIOS_PVT_DATA;
+
+       memset((void *)megacfg->mega_buffer, 0, sizeof(megacfg->mega_buffer));
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+       dma_handle = pci_map_single(megacfg->dev, (void *)megacfg->mega_buffer,
+                             (2 * 1024L), PCI_DMA_FROMDEVICE);
+
+       mboxp->xferaddr = dma_handle;
+#else
+       mboxp->xferaddr = virt_to_bus((void *)megacfg->mega_buffer);
+#endif
+
+       megacfg->boot_ldrv_enabled = 0;
+       megacfg->boot_ldrv = 0;
+
+       megacfg->boot_pdrv_enabled = 0;
+       megacfg->boot_pdrv_ch = 0;
+       megacfg->boot_pdrv_tgt = 0;
+
+       if( megaIssueCmd(megacfg, mbox, NULL, 0) == 0 ) {
+               prv_bios_data = (struct private_bios_data *)megacfg->mega_buffer;
+
+               cksum = 0;
+               cksum_p = (u8 *)prv_bios_data;
+               for( i = 0; i < 14; i++ ) {
+                       cksum += *cksum_p++;
+               }
+
+               if( prv_bios_data->cksum == (u16)(0-cksum) ) {
+
+                       /*
+                        * If MSB is set, a physical drive is set as boot device
+                        */
+                       if( prv_bios_data->boot_drv & 0x80 ) {
+                               megacfg->boot_pdrv_enabled = 1;
+                               boot_pdrv = prv_bios_data->boot_drv & 0x7F;
+                               megacfg->boot_pdrv_ch = boot_pdrv / 16;
+                               megacfg->boot_pdrv_tgt = boot_pdrv % 16;
+                       }
+                       else {
+                               megacfg->boot_ldrv_enabled = 1;
+                               megacfg->boot_ldrv = prv_bios_data->boot_drv;
+                       }
+               }
+       }
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+       pci_unmap_single(megacfg->dev, dma_handle,
+                                 (2 * 1024L), PCI_DMA_FROMDEVICE);
+#endif
+
+}
+
+
+static void mega_reorder_hosts (void)
+{
+       struct Scsi_Host *shpnt;
+       struct Scsi_Host *shone;
+       struct Scsi_Host *shtwo;
+       mega_host_config *boot_host;
+       int i;
+
+       /*
+        * Find the (first) host which has it's BIOS enabled
+        */
+       boot_host = NULL;
+       for (i = 0; i < MAX_CONTROLLERS; i++) {
+               if (mega_hbas[i].is_bios_enabled) {
+                       boot_host = mega_hbas[i].hostdata_addr;
+                       break;
+               }
+       }
+
+       if (boot_host == NULL) {
+               printk (KERN_WARNING "megaraid: no BIOS enabled.\n");
+               return;
+       }
+
+       /*
+        * Traverse through the list of SCSI hosts for our HBA locations
+        */
+       shone = shtwo = NULL;
+       for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) {
+               /* Is it one of ours? */
+               for (i = 0; i < MAX_CONTROLLERS; i++) {
+                       if ((mega_host_config *) shpnt->hostdata ==
+                           mega_hbas[i].hostdata_addr) {
+                               /* Does this one has BIOS enabled */
+                               if (mega_hbas[i].hostdata_addr == boot_host) {
+
+                                       /* Are we first */
+                                       if (shtwo == NULL)      /* Yes! */
+                                               return;
+                                       else {  /* :-( */
+                                               shone = shpnt;
+                                       }
+                               } else {
+                                       if (!shtwo) {
+                                               /* were we here before? xchng first */
+                                               shtwo = shpnt;
+                                       }
+                               }
+                               break;
+                       }
+               }
+               /*
+                * Have we got the boot host and one which does not have the bios
+                * enabled.
+                */
+               if (shone && shtwo)
+                       break;
+       }
+       if (shone && shtwo) {
+               mega_swap_hosts (shone, shtwo);
+       }
+
+       return;
+}
+
+static void mega_swap_hosts (struct Scsi_Host *shone, struct Scsi_Host *shtwo)
+{
+       struct Scsi_Host *prevtoshtwo;
+       struct Scsi_Host *prevtoshone;
+       struct Scsi_Host *save = NULL;;
+
+       /* Are these two nodes adjacent */
+       if (shtwo->next == shone) {
+
+               if (shtwo == scsi_hostlist && shone->next == NULL) {
+
+                       /* just two nodes */
+                       scsi_hostlist = shone;
+                       shone->next = shtwo;
+                       shtwo->next = NULL;
+               } else if (shtwo == scsi_hostlist) {
+                       /* first two nodes of the list */
+
+                       scsi_hostlist = shone;
+                       shtwo->next = shone->next;
+                       scsi_hostlist->next = shtwo;
+               } else if (shone->next == NULL) {
+                       /* last two nodes of the list */
+
+                       prevtoshtwo = scsi_hostlist;
+
+                       while (prevtoshtwo->next != shtwo)
+                               prevtoshtwo = prevtoshtwo->next;
+
+                       prevtoshtwo->next = shone;
+                       shone->next = shtwo;
+                       shtwo->next = NULL;
+               } else {
+                       prevtoshtwo = scsi_hostlist;
+
+                       while (prevtoshtwo->next != shtwo)
+                               prevtoshtwo = prevtoshtwo->next;
+
+                       prevtoshtwo->next = shone;
+                       shtwo->next = shone->next;
+                       shone->next = shtwo;
+               }
+
+       } else if (shtwo == scsi_hostlist && shone->next == NULL) {
+               /* shtwo at head, shone at tail, not adjacent */
+
+               prevtoshone = scsi_hostlist;
+
+               while (prevtoshone->next != shone)
+                       prevtoshone = prevtoshone->next;
+
+               scsi_hostlist = shone;
+               shone->next = shtwo->next;
+               prevtoshone->next = shtwo;
+               shtwo->next = NULL;
+       } else if (shtwo == scsi_hostlist && shone->next != NULL) {
+               /* shtwo at head, shone is not at tail */
+
+               prevtoshone = scsi_hostlist;
+               while (prevtoshone->next != shone)
+                       prevtoshone = prevtoshone->next;
+
+               scsi_hostlist = shone;
+               prevtoshone->next = shtwo;
+               save = shtwo->next;
+               shtwo->next = shone->next;
+               shone->next = save;
+       } else if (shone->next == NULL) {
+               /* shtwo not at head, shone at tail */
+
+               prevtoshtwo = scsi_hostlist;
+               prevtoshone = scsi_hostlist;
+
+               while (prevtoshtwo->next != shtwo)
+                       prevtoshtwo = prevtoshtwo->next;
+               while (prevtoshone->next != shone)
+                       prevtoshone = prevtoshone->next;
+
+               prevtoshtwo->next = shone;
+               shone->next = shtwo->next;
+               prevtoshone->next = shtwo;
+               shtwo->next = NULL;
+
+       } else {
+               prevtoshtwo = scsi_hostlist;
+               prevtoshone = scsi_hostlist;
+               save = NULL;;
+
+               while (prevtoshtwo->next != shtwo)
+                       prevtoshtwo = prevtoshtwo->next;
+               while (prevtoshone->next != shone)
+                       prevtoshone = prevtoshone->next;
+
+               prevtoshtwo->next = shone;
+               save = shone->next;
+               shone->next = shtwo->next;
+               prevtoshone->next = shtwo;
+               shtwo->next = save;
+       }
+       return;
+}
+
+static inline void mega_freeSgList (mega_host_config * megaCfg)
+{
+       int i;
+
+       for (i = 0; i < megaCfg->max_cmds; i++) {
+               if (megaCfg->scbList[i].sgList)
+                       pci_free_consistent (megaCfg->dev,
+                                            sizeof (mega_64sglist) *
+                                            MAX_SGLIST,
+                                            megaCfg->scbList[i].sgList,
+                                            megaCfg->scbList[i].
+                                            dma_sghandle64);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) /* 0x020400 */
+                       kfree (megaCfg->scbList[i].sgList);     /* free sgList */
+#endif
+       }
+}
+
+/*----------------------------------------------
+ * Get information about the card/driver
+ *----------------------------------------------*/
+const char *megaraid_info (struct Scsi_Host *pSHost)
+{
+       static char buffer[512];
+       mega_host_config *megaCfg;
+
+       megaCfg = (mega_host_config *) pSHost->hostdata;
+
+       sprintf (buffer,
+                "LSI Logic MegaRAID %s %d commands %d targs %d chans %d luns",
+                megaCfg->fwVer, megaCfg->productInfo.MaxConcCmds,
+                megaCfg->host->max_id-1, megaCfg->host->max_channel,
+                megaCfg->host->max_lun);
+       return buffer;
+}
+
+/*-----------------------------------------------------------------
+ * Perform a SCSI command
+ * Mailbox area:
+ *   00 01 command
+ *   01 01 command id
+ *   02 02 # of sectors
+ *   04 04 logical bus address
+ *   08 04 physical buffer address
+ *   0C 01 logical drive #
+ *   0D 01 length of scatter/gather list
+ *   0E 01 reserved
+ *   0F 01 mailbox busy
+ *   10 01 numstatus byte
+ *   11 01 status byte
+ *-----------------------------------------------------------------*/
+int megaraid_queue (Scsi_Cmnd * SCpnt, void (*pktComp) (Scsi_Cmnd *))
+{
+       DRIVER_LOCK_T mega_host_config * megaCfg;
+       mega_scb *pScb;
+       char *user_area = NULL;
+
+       megaCfg = (mega_host_config *) SCpnt->host->hostdata;
+       DRIVER_LOCK (megaCfg);
+
+#if 0
+       if (!(megaCfg->flag & (1L << SCpnt->channel))) {
+               if (SCpnt->channel < megaCfg->productInfo.SCSIChanPresent)
+                       printk ( KERN_NOTICE
+                               "scsi%d: scanning channel %d for devices.\n",
+                               megaCfg->host->host_no, SCpnt->channel);
+               else
+                       printk ( KERN_NOTICE
+                               "scsi%d: scanning virtual channel %d for logical drives.\n",
+                               megaCfg->host->host_no,
+                               SCpnt->channel-megaCfg->productInfo.SCSIChanPresent+1);
+
+               megaCfg->flag |= (1L << SCpnt->channel);
+       }
+#endif
+
+       SCpnt->scsi_done = pktComp;
+
+       if (mega_driver_ioctl (megaCfg, SCpnt))
+               return 0;
+
+       /* If driver in abort or reset.. cancel this command */
+       if (megaCfg->flag & IN_ABORT) {
+               SCpnt->result = (DID_ABORT << 16);
+               /* Add Scsi_Command to end of completed queue */
+               if (megaCfg->qCompletedH == NULL) {
+                       megaCfg->qCompletedH = megaCfg->qCompletedT = SCpnt;
+               } else {
+                       megaCfg->qCompletedT->host_scribble =
+                           (unsigned char *) SCpnt;
+                       megaCfg->qCompletedT = SCpnt;
+               }
+               megaCfg->qCompletedT->host_scribble = (unsigned char *) NULL;
+               megaCfg->qCcnt++;
+
+               DRIVER_UNLOCK (megaCfg);
+               return 0;
+       } else if (megaCfg->flag & IN_RESET) {
+               SCpnt->result = (DID_RESET << 16);
+               /* Add Scsi_Command to end of completed queue */
+               if (megaCfg->qCompletedH == NULL) {
+                       megaCfg->qCompletedH = megaCfg->qCompletedT = SCpnt;
+               } else {
+                       megaCfg->qCompletedT->host_scribble =
+                           (unsigned char *) SCpnt;
+                       megaCfg->qCompletedT = SCpnt;
+               }
+               megaCfg->qCompletedT->host_scribble = (unsigned char *) NULL;
+               megaCfg->qCcnt++;
+
+               DRIVER_UNLOCK (megaCfg);
+               return 0;
+       }
+
+       megaCfg->flag |= IN_QUEUE;
+       /* Allocate and build a SCB request */
+       if ((pScb = mega_build_cmd (megaCfg, SCpnt)) != NULL) {
+
+               /*
+                * Check if the HBA is in quiescent state, e.g., during a delete
+                * logical drive opertion. If it is, queue the commands in the
+                * internal queue until the delete operation is complete.
+                */
+               if( ! megaCfg->quiescent ) {
+                       /* Add SCB to the head of the pending queue */
+                       if (megaCfg->qPendingH == NULL) {
+                               megaCfg->qPendingH = megaCfg->qPendingT = pScb;
+                       } else {
+                               megaCfg->qPendingT->next = pScb;
+                               megaCfg->qPendingT = pScb;
+                       }
+                       megaCfg->qPendingT->next = NULL;
+                       megaCfg->qPcnt++;
+
+                       if (mega_runpendq (megaCfg) == -1) {
+                               DRIVER_UNLOCK (megaCfg);
+                               return 0;
+                       }
+               }
+               else {
+                       /* Add SCB to the internal queue */
+                       if (megaCfg->int_qh == NULL) {
+                               megaCfg->int_qh = megaCfg->int_qt = pScb;
+                       } else {
+                               megaCfg->int_qt->next = pScb;
+                               megaCfg->int_qt = pScb;
+                       }
+                       megaCfg->int_qt->next = NULL;
+                       megaCfg->int_qlen++;
+               }
+
+               if (pScb->SCpnt->cmnd[0] == M_RD_IOCTL_CMD_NEW) {
+#if XENO_KILLED
+                       init_MUTEX_LOCKED (&pScb->ioctl_sem);
+#endif
+                       spin_unlock_irq (&io_request_lock);
+#if XENO_KILLED
+                       down (&pScb->ioctl_sem);
+#endif
+               user_area = (char *)*((u32*)&pScb->SCpnt->cmnd[4]);
+                       if (copy_to_user
+                           (user_area, pScb->buff_ptr, pScb->iDataSize)) {
+                               printk
+                                   ("megaraid: Error copying ioctl return value to user buffer.\n");
+                               pScb->SCpnt->result = (DID_ERROR << 16);
+                       }
+                       spin_lock_irq (&io_request_lock);
+                       DRIVER_LOCK (megaCfg);
+                       kfree (pScb->buff_ptr);
+                       pScb->buff_ptr = NULL;
+                       mega_cmd_done (megaCfg, pScb, pScb->SCpnt->result);
+                       mega_rundoneq (megaCfg);
+                       mega_runpendq (megaCfg);
+                       DRIVER_UNLOCK (megaCfg);
+               }
+
+               megaCfg->flag &= ~IN_QUEUE;
+
+       }
+
+       DRIVER_UNLOCK (megaCfg);
+       return 0;
+}
+
+/*----------------------------------------------------------------------
+ * Issue a blocking command to the controller
+ *----------------------------------------------------------------------*/
+#if XENO_KILLED
+volatile static int internal_done_flag = 0;
+volatile static int internal_done_errcode = 0;
+
+static DECLARE_WAIT_QUEUE_HEAD (internal_wait);
+
+static void internal_done (Scsi_Cmnd * SCpnt)
+{
+       internal_done_errcode = SCpnt->result;
+       internal_done_flag++;
+       wake_up (&internal_wait);
+}
+
+/* shouldn't be used, but included for completeness */
+
+int megaraid_command (Scsi_Cmnd * SCpnt)
+{
+       internal_done_flag = 0;
+
+       /* Queue command, and wait until it has completed */
+       megaraid_queue (SCpnt, internal_done);
+
+       while (!internal_done_flag) {
+               interruptible_sleep_on (&internal_wait);
+       }
+
+       return internal_done_errcode;
+}
+#endif
+
+/*---------------------------------------------------------------------
+ * Abort a previous SCSI request
+ *---------------------------------------------------------------------*/
+int megaraid_abort (Scsi_Cmnd * SCpnt)
+{
+       mega_host_config *megaCfg;
+       int rc;                 /*, idx; */
+       mega_scb *pScb;
+
+       rc = SCSI_ABORT_NOT_RUNNING;
+
+       megaCfg = (mega_host_config *) SCpnt->host->hostdata;
+
+       megaCfg->flag |= IN_ABORT;
+
+       for (pScb = megaCfg->qPendingH; pScb; pScb = pScb->next) {
+               if (pScb->SCpnt == SCpnt) {
+                       /* Found an aborting command */
+#if DEBUG
+                       showMbox (pScb);
+#endif
+
+       /*
+        * If the command is queued to be issued to the firmware, abort the scsi cmd,
+        * If the command is already aborted in a previous call to the _abort entry
+        *  point, return SCSI_ABORT_SNOOZE, suggesting a reset.
+        * If the command is issued to the firmware, which might complete after
+        *  some time, we will mark the scb as aborted, and return to the mid layer,
+        *  that abort could not be done.
+        *  In the ISR, when this command actually completes, we will perform a normal
+        *  completion.
+        *
+        * Oct 27, 1999
+        */
+
+                       switch (pScb->state) {
+                       case SCB_ABORTED:       /* Already aborted */
+                               rc = SCSI_ABORT_SNOOZE;
+                               break;
+                       case SCB_ISSUED:        /* Waiting on ISR result */
+                               rc = SCSI_ABORT_NOT_RUNNING;
+                               pScb->state = SCB_ABORTED;
+                               break;
+                       case SCB_ACTIVE:        /* still on the pending queue */
+                               mega_freeSCB (megaCfg, pScb);
+                               SCpnt->result = (DID_ABORT << 16);
+                               if (megaCfg->qCompletedH == NULL) {
+                                       megaCfg->qCompletedH =
+                                           megaCfg->qCompletedT = SCpnt;
+                               } else {
+                                       megaCfg->qCompletedT->host_scribble =
+                                           (unsigned char *) SCpnt;
+                                       megaCfg->qCompletedT = SCpnt;
+                               }
+                               megaCfg->qCompletedT->host_scribble =
+                                   (unsigned char *) NULL;
+                               megaCfg->qCcnt++;
+                               rc = SCSI_ABORT_SUCCESS;
+                               break;
+                       default:
+                               printk
+                                   ("megaraid_abort: unknown command state!!\n");
+                               rc = SCSI_ABORT_NOT_RUNNING;
+                               break;
+                       }
+                       break;
+               }
+       }
+
+       megaCfg->flag &= ~IN_ABORT;
+
+#if DEBUG
+       if (megaCfg->flag & IN_QUEUE)
+               printk ("ma:flag is in queue\n");
+       if (megaCfg->qCompletedH == NULL)
+               printk ("ma:qchead == null\n");
+#endif
+
+       /*
+        * This is required here to complete any completed requests to be communicated
+        * over to the mid layer.
+        * Calling just mega_rundoneq() did not work.
+        */
+       if (megaCfg->qCompletedH) {
+               SCpnt = megaCfg->qCompletedH;
+               megaCfg->qCompletedH = (Scsi_Cmnd *) SCpnt->host_scribble;
+               megaCfg->qCcnt--;
+
+               SCpnt->host_scribble = (unsigned char *) NULL;
+               /* Callback */
+               callDone (SCpnt);
+       }
+       mega_rundoneq (megaCfg);
+
+       return rc;
+}
+
+/*---------------------------------------------------------------------
+ * Reset a previous SCSI request
+ *---------------------------------------------------------------------*/
+
+int megaraid_reset (Scsi_Cmnd * SCpnt, unsigned int rstflags)
+{
+       mega_host_config *megaCfg;
+       int idx;
+       int rc;
+       mega_scb *pScb;
+
+       rc = SCSI_RESET_NOT_RUNNING;
+       megaCfg = (mega_host_config *) SCpnt->host->hostdata;
+
+       megaCfg->flag |= IN_RESET;
+
+       printk
+           ("megaraid_RESET: %.08lx cmd=%.02x <c=%d.t=%d.l=%d>, flag = %x\n",
+            SCpnt->serial_number, SCpnt->cmnd[0], SCpnt->channel,
+            SCpnt->target, SCpnt->lun, rstflags);
+
+       TRACE (("RESET: %.08lx %.02x <%d.%d.%d>\n",
+               SCpnt->serial_number, SCpnt->cmnd[0], SCpnt->channel,
+               SCpnt->target, SCpnt->lun));
+
+       /*
+        * Walk list of SCBs for any that are still outstanding
+        */
+       for (idx = 0; idx < megaCfg->max_cmds; idx++) {
+               if (megaCfg->scbList[idx].state != SCB_FREE) {
+                       SCpnt = megaCfg->scbList[idx].SCpnt;
+                       pScb = &megaCfg->scbList[idx];
+                       if (SCpnt != NULL) {
+                               pScb->state = SCB_RESET;
+                               break;
+                       }
+               }
+       }
+
+       megaCfg->flag &= ~IN_RESET;
+
+       mega_rundoneq (megaCfg);
+       return rc;
+}
+
+#ifdef CONFIG_PROC_FS
+/* Following code handles /proc fs  */
+static int proc_printf (mega_host_config * megaCfg, const char *fmt, ...)
+{
+       va_list args;
+       int i;
+
+       if (megaCfg->procidx > PROCBUFSIZE)
+               return 0;
+
+       va_start (args, fmt);
+       i = vsprintf ((megaCfg->procbuf + megaCfg->procidx), fmt, args);
+       va_end (args);
+
+       megaCfg->procidx += i;
+       return i;
+}
+
+static int proc_read_config (char *page, char **start, off_t offset,
+                 int count, int *eof, void *data)
+{
+
+       mega_host_config *megaCfg = (mega_host_config *) data;
+
+       *start = page;
+
+       if (megaCfg->productInfo.ProductName[0] != 0)
+               proc_printf (megaCfg, "%s\n", megaCfg->productInfo.ProductName);
+
+       proc_printf (megaCfg, "Controller Type: ");
+
+       if (megaCfg->flag & BOARD_QUARTZ)
+               proc_printf (megaCfg, "438/466/467/471/493\n");
+       else
+               proc_printf (megaCfg, "418/428/434\n");
+
+       if (megaCfg->flag & BOARD_40LD)
+               proc_printf (megaCfg,
+                            "Controller Supports 40 Logical Drives\n");
+
+       if (megaCfg->flag & BOARD_64BIT)
+               proc_printf (megaCfg,
+                            "Controller / Driver uses 64 bit memory addressing\n");
+
+       proc_printf (megaCfg, "Base = %08x, Irq = %d, ", megaCfg->base,
+                    megaCfg->host->irq);
+
+       proc_printf (megaCfg, "Logical Drives = %d, Channels = %d\n",
+                    megaCfg->numldrv, megaCfg->productInfo.SCSIChanPresent);
+
+       proc_printf (megaCfg, "Version =%s:%s, DRAM = %dMb\n",
+                    megaCfg->fwVer, megaCfg->biosVer,
+                    megaCfg->productInfo.DramSize);
+
+       proc_printf (megaCfg,
+                    "Controller Queue Depth = %d, Driver Queue Depth = %d\n",
+                    megaCfg->productInfo.MaxConcCmds, megaCfg->max_cmds);
+       COPY_BACK;
+       return count;
+}
+
+static int proc_read_stat (char *page, char **start, off_t offset,
+               int count, int *eof, void *data)
+{
+       int i;
+       mega_host_config *megaCfg = (mega_host_config *) data;
+
+       *start = page;
+
+       proc_printf (megaCfg, "Statistical Information for this controller\n");
+       proc_printf (megaCfg, "Interrupts Collected = %lu\n",
+                    megaCfg->nInterrupts);
+
+       for (i = 0; i < megaCfg->numldrv; i++) {
+               proc_printf (megaCfg, "Logical Drive %d:\n", i);
+
+               proc_printf (megaCfg,
+                            "\tReads Issued = %lu, Writes Issued = %lu\n",
+                            megaCfg->nReads[i], megaCfg->nWrites[i]);
+
+               proc_printf (megaCfg,
+                            "\tSectors Read = %lu, Sectors Written = %lu\n\n",
+                            megaCfg->nReadBlocks[i], megaCfg->nWriteBlocks[i]);
+
+       }
+
+       COPY_BACK;
+       return count;
+}
+
+static int proc_read_status (char *page, char **start, off_t offset,
+                 int count, int *eof, void *data)
+{
+       mega_host_config *megaCfg = (mega_host_config *) data;
+       *start = page;
+
+       proc_printf (megaCfg, "TBD\n");
+       COPY_BACK;
+       return count;
+}
+
+static int proc_read_mbox (char *page, char **start, off_t offset,
+               int count, int *eof, void *data)
+{
+
+       mega_host_config *megaCfg = (mega_host_config *) data;
+       volatile mega_mailbox *mbox = megaCfg->mbox;
+
+       *start = page;
+
+       proc_printf (megaCfg, "Contents of Mail Box Structure\n");
+       proc_printf (megaCfg, "  Fw Command   = 0x%02x\n", mbox->cmd);
+       proc_printf (megaCfg, "  Cmd Sequence = 0x%02x\n", mbox->cmdid);
+       proc_printf (megaCfg, "  No of Sectors= %04d\n", mbox->numsectors);
+       proc_printf (megaCfg, "  LBA          = 0x%02x\n", mbox->lba);
+       proc_printf (megaCfg, "  DTA          = 0x%08x\n", mbox->xferaddr);
+       proc_printf (megaCfg, "  Logical Drive= 0x%02x\n", mbox->logdrv);
+       proc_printf (megaCfg, "  No of SG Elmt= 0x%02x\n", mbox->numsgelements);
+       proc_printf (megaCfg, "  Busy         = %01x\n", mbox->busy);
+       proc_printf (megaCfg, "  Status       = 0x%02x\n", mbox->status);
+
+       /* proc_printf(megaCfg, "Dump of MailBox\n");
+       for (i = 0; i < 16; i++)
+               proc_printf(megaCfg, "%02x ",*(mbox + i));
+
+       proc_printf(megaCfg, "\n\nNumber of Status = %02d\n",mbox->numstatus);
+
+       for (i = 0; i < 46; i++) {
+               proc_printf(megaCfg,"%02d ",*(mbox + 16 + i));
+        if (i%16)
+                proc_printf(megaCfg,"\n");
+       }
+
+       if (!mbox->numsgelements) {
+               dta = phys_to_virt(mbox->xferaddr);
+               for (i = 0; i < mbox->numsgelements; i++)
+                       if (dta) {
+                               proc_printf(megaCfg,"Addr = %08x\n", (ulong)*(dta + i));                        proc_printf(megaCfg,"Length = %08x\n",
+                                       (ulong)*(dta + i + 4));
+                       }
+       }*/
+       COPY_BACK;
+       return count;
+}
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0) /*0x20300 */
+#define CREATE_READ_PROC(string, fxn) create_proc_read_entry(string, \
+                                         S_IRUSR | S_IFREG,\
+                                         controller_proc_dir_entry,\
+                                         fxn, megaCfg)
+#else
+#define CREATE_READ_PROC(string, fxn) create_proc_read_entry(string,S_IRUSR | S_IFREG, controller_proc_dir_entry, fxn, megaCfg)
+
+static struct proc_dir_entry *
+create_proc_read_entry (const char *string,
+                       int mode,
+                       struct proc_dir_entry *parent,
+                       read_proc_t * fxn, mega_host_config * megaCfg)
+{
+       struct proc_dir_entry *temp = NULL;
+
+       temp = kmalloc (sizeof (struct proc_dir_entry), GFP_KERNEL);
+       if (!temp)
+               return NULL;
+       memset (temp, 0, sizeof (struct proc_dir_entry));
+
+       if ((temp->name = kmalloc (strlen (string) + 1, GFP_KERNEL)) == NULL) {
+               kfree (temp);
+               return NULL;
+       }
+
+       strcpy ((char *) temp->name, string);
+       temp->namelen = strlen (string);
+       temp->mode = mode; /*S_IFREG | S_IRUSR */ ;
+       temp->data = (void *) megaCfg;
+       temp->read_proc = fxn;
+       proc_register (parent, temp);
+       return temp;
+}
+#endif
+
+static void mega_create_proc_entry (int index, struct proc_dir_entry *parent)
+{
+       u_char string[64] = { 0 };
+       mega_host_config *megaCfg = megaCtlrs[index];
+       struct proc_dir_entry *controller_proc_dir_entry = NULL;
+
+       sprintf (string, "%d", index);
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0) /*0x20300 */
+       controller_proc_dir_entry =
+           megaCfg->controller_proc_dir_entry = proc_mkdir (string, parent);
+#else
+       controller_proc_dir_entry =
+           megaCfg->controller_proc_dir_entry =
+           create_proc_entry (string, S_IFDIR | S_IRUGO | S_IXUGO, parent);
+#endif
+
+       if (!controller_proc_dir_entry)
+               printk ("\nmegaraid: proc_mkdir failed\n");
+       else {
+               megaCfg->proc_read =
+                   CREATE_READ_PROC ("config", proc_read_config);
+               megaCfg->proc_status =
+                   CREATE_READ_PROC ("status", proc_read_status);
+               megaCfg->proc_stat = CREATE_READ_PROC ("stat", proc_read_stat);
+               megaCfg->proc_mbox =
+                   CREATE_READ_PROC ("mailbox", proc_read_mbox);
+       }
+
+}
+#endif                         /* CONFIG_PROC_FS */
+
+/*-------------------------------------------------------------
+ * Return the disk geometry for a particular disk
+ * Input:
+ *   Disk *disk - Disk geometry
+ *   kdev_t dev - Device node
+ *   int *geom  - Returns geometry fields
+ *     geom[0] = heads
+ *     geom[1] = sectors
+ *     geom[2] = cylinders
+ *-------------------------------------------------------------*/
+int megaraid_biosparam (Disk * disk, kdev_t dev, int *geom)
+{
+       int heads, sectors, cylinders;
+       mega_host_config *megaCfg;
+
+       /* Get pointer to host config structure */
+       megaCfg = (mega_host_config *) disk->device->host->hostdata;
+
+       if( IS_RAID_CH(megaCfg, disk->device->channel)) {
+                       /* Default heads (64) & sectors (32) */
+                       heads = 64;
+                       sectors = 32;
+                       cylinders = disk->capacity / (heads * sectors);
+
+                       /* Handle extended translation size for logical drives > 1Gb */
+                       if (disk->capacity >= 0x200000) {
+                               heads = 255;
+                               sectors = 63;
+                               cylinders = disk->capacity / (heads * sectors);
+                       }
+
+                       /* return result */
+                       geom[0] = heads;
+                       geom[1] = sectors;
+                       geom[2] = cylinders;
+       }
+       else {
+               if( mega_partsize(disk, dev, geom) == 0 ) return 0;
+
+               printk(KERN_WARNING
+                               "megaraid: invalid partition on this disk on channel %d\n",
+                               disk->device->channel);
+
+               /* Default heads (64) & sectors (32) */
+               heads = 64;
+               sectors = 32;
+               cylinders = disk->capacity / (heads * sectors);
+
+               /* Handle extended translation size for logical drives > 1Gb */
+               if (disk->capacity >= 0x200000) {
+                       heads = 255;
+                       sectors = 63;
+                       cylinders = disk->capacity / (heads * sectors);
+               }
+
+               /* return result */
+               geom[0] = heads;
+               geom[1] = sectors;
+               geom[2] = cylinders;
+       }
+
+       return 0;
+}
+
+/*
+ * Function : static int mega_partsize(Disk * disk, kdev_t dev, int *geom)
+ *
+ * Purpose : to determine the BIOS mapping used to create the partition
+ *                     table, storing the results (cyls, hds, and secs) in geom
+ *
+ * Note:       Code is picked from scsicam.h
+ *
+ * Returns : -1 on failure, 0 on success.
+ */
+static int
+mega_partsize(Disk * disk, kdev_t dev, int *geom)
+{
+#if XENO_KILLED
+       struct buffer_head *bh;
+       struct partition *p, *largest = NULL;
+       int i, largest_cyl;
+       int heads, cyls, sectors;
+       int capacity = disk->capacity;
+
+       int ma = MAJOR(dev);
+       int mi = (MINOR(dev) & ~0xf);
+
+       int block = 1024; 
+
+
+       if(blksize_size[ma])
+               block = blksize_size[ma][mi];
+               
+       if(!(bh = bread(MKDEV(ma,mi), 0, block)))
+               return -1;
+
+       if( *(unsigned short *)(bh->b_data + 510) == 0xAA55 ) {
+
+               for( largest_cyl = -1, p = (struct partition *)(0x1BE + bh->b_data),
+                               i = 0; i < 4; ++i, ++p) {
+
+                       if (!p->sys_ind) continue;
+
+                       cyls = p->end_cyl + ((p->end_sector & 0xc0) << 2);
+
+                       if(cyls >= largest_cyl) {
+                               largest_cyl = cyls;
+                               largest = p;
+                       }
+               }
+       }
+
+       if (largest) {
+               heads = largest->end_head + 1;
+               sectors = largest->end_sector & 0x3f;
+
+               if (heads == 0 || sectors == 0) {
+                       brelse(bh);
+                       return -1;
+               }
+
+               cyls = capacity/(heads * sectors);
+
+               geom[0] = heads;
+               geom[1] = sectors;
+               geom[2] = cyls;
+
+               brelse(bh);
+               return 0;
+       }
+
+       brelse(bh);
+#endif
+       return -1;
+}
+
+
+/*
+ * This routine will be called when the use has done a forced shutdown on the
+ * system. Flush the Adapter cache, that's the most we can do.
+ */
+static int megaraid_reboot_notify (struct notifier_block *this, unsigned long code,
+                       void *unused)
+{
+       struct Scsi_Host *pSHost;
+       mega_host_config *megaCfg;
+       mega_mailbox *mbox;
+       u_char mboxData[16];
+       int i;
+
+       if (code == SYS_DOWN || code == SYS_HALT) {
+               for (i = 0; i < numCtlrs; i++) {
+                       pSHost = megaCtlrs[i]->host;
+
+                       megaCfg = (mega_host_config *) pSHost->hostdata;
+                       mbox = (mega_mailbox *) mboxData;
+
+                       /* Flush cache to disk */
+                       memset (mbox, 0, 16);
+                       mboxData[0] = 0xA;
+
+                       /*
+                        * Free irq, otherwise extra interrupt is generated
+                        */
+                       free_irq (megaCfg->host->irq, megaCfg);
+
+                       /*
+                          * Issue a blocking (interrupts disabled) command to
+                          * the card
+                        */
+                       megaIssueCmd (megaCfg, mboxData, NULL, 0);
+               }
+       }
+       return NOTIFY_DONE;
+}
+
+static int mega_init_scb (mega_host_config * megacfg)
+{
+       int idx;
+
+#if DEBUG
+       if (megacfg->max_cmds >= MAX_COMMANDS) {
+               printk ("megaraid:ctlr max cmds = %x : MAX_CMDS = %x",
+                       megacfg->max_cmds, MAX_COMMANDS);
+       }
+#endif
+
+       for (idx = megacfg->max_cmds - 1; idx >= 0; idx--) {
+
+               megacfg->scbList[idx].idx = idx;
+
+               /*
+                * ISR will make this flag zero to indicate the command has been
+                * completed. This is only for user ioctl calls. Rest of the driver
+                * and the mid-layer operations are not connected with this flag.
+                */
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+               megacfg->scbList[idx].sgList =
+                   pci_alloc_consistent (megacfg->dev,
+                                         sizeof (mega_64sglist) * MAX_SGLIST,
+                                         &(megacfg->scbList[idx].
+                                           dma_sghandle64));
+
+               megacfg->scbList[idx].sg64List =
+                   (mega_64sglist *) megacfg->scbList[idx].sgList;
+#else
+               megacfg->scbList[idx].sgList = kmalloc (sizeof (mega_sglist) * MAX_SGLIST, GFP_ATOMIC | GFP_DMA);
+#endif
+
+               if (megacfg->scbList[idx].sgList == NULL) {
+                       printk (KERN_WARNING
+                               "Can't allocate sglist for id %d\n", idx);
+                       mega_freeSgList (megacfg);
+                       return -1;
+               }
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+               megacfg->scbList[idx].pthru = pci_alloc_consistent (megacfg->dev,
+                                         sizeof (mega_passthru),
+                                         &(megacfg->scbList[idx].
+                                           dma_passthruhandle64));
+
+               if (megacfg->scbList[idx].pthru == NULL) {
+                       printk (KERN_WARNING
+                               "Can't allocate passthru for id %d\n", idx);
+               }
+
+               megacfg->scbList[idx].epthru =
+                       pci_alloc_consistent(
+                               megacfg->dev, sizeof(mega_ext_passthru),
+                               &(megacfg->scbList[idx].dma_ext_passthruhandle64)
+                       );
+
+               if (megacfg->scbList[idx].epthru == NULL) {
+                       printk (KERN_WARNING
+                               "Can't allocate extended passthru for id %d\n", idx);
+               }
+               /* 
+                * Allocate a 256 Byte Bounce Buffer for handling INQ/RD_CAPA 
+                */
+               megacfg->scbList[idx].bounce_buffer = pci_alloc_consistent (megacfg->dev,
+                                         256,
+                                         &(megacfg->scbList[idx].
+                                           dma_bounce_buffer));
+
+               if (!megacfg->scbList[idx].bounce_buffer)
+                       printk
+                           ("megaraid: allocation for bounce buffer failed\n");
+
+               megacfg->scbList[idx].dma_type = M_RD_DMA_TYPE_NONE;
+#endif
+
+               if (idx < MAX_COMMANDS) {
+                       /*
+                        * Link to free list
+                        * lock not required since we are loading the driver, so no
+                        * commands possible right now.
+                        */
+                       enq_scb_freelist (megacfg, &megacfg->scbList[idx],
+                                         NO_LOCK, INTR_ENB);
+
+               }
+       }
+
+       return 0;
+}
+
+/*
+ * Enqueues a SCB
+ */
+static void enq_scb_freelist (mega_host_config * megacfg, mega_scb * scb, int lock,
+                 int intr)
+{
+
+       if (lock == INTERNAL_LOCK || intr == INTR_DIS) {
+               if (intr == INTR_DIS)
+                       spin_lock_irq (&megacfg->lock_free);
+               else
+                       spin_lock (&megacfg->lock_free);
+       }
+
+       scb->state = SCB_FREE;
+       scb->SCpnt = NULL;
+
+       if (megacfg->qFreeH == (mega_scb *) NULL) {
+               megacfg->qFreeH = megacfg->qFreeT = scb;
+       } else {
+               megacfg->qFreeT->next = scb;
+               megacfg->qFreeT = scb;
+       }
+
+       megacfg->qFreeT->next = NULL;
+       megacfg->qFcnt++;
+
+       if (lock == INTERNAL_LOCK || intr == INTR_DIS) {
+               if (intr == INTR_DIS)
+                       spin_unlock_irq (&megacfg->lock_free);
+               else
+                       spin_unlock (&megacfg->lock_free);
+       }
+}
+
+/*
+ * Routines for the character/ioctl interface to the driver
+ */
+static int megadev_open (struct inode *inode, struct file *filep)
+{
+       MOD_INC_USE_COUNT;
+       return 0;               /* success */
+}
+
+static int megadev_ioctl_entry (struct inode *inode, struct file *filep,
+                    unsigned int cmd, unsigned long arg)
+{
+       int ret = -1;
+
+       /*
+        * We do not allow parallel ioctls to the driver as of now.
+        */
+#if XENO_KILLED // XXX JWS killed the locking!
+       down (&mimd_entry_mtx);
+       ret = megadev_ioctl (inode, filep, cmd, arg);
+       up (&mimd_entry_mtx);
+#else
+       ret = megadev_ioctl (inode, filep, cmd, arg);
+#endif
+
+       return ret;
+
+}
+
+static int megadev_ioctl (struct inode *inode, struct file *filep,
+              unsigned int cmd, unsigned long arg)
+{
+       int adapno;
+       kdev_t dev;
+       u32 inlen;
+       struct uioctl_t ioc;
+       char *kvaddr = NULL;
+       int nadap = numCtlrs;
+       u8 opcode;
+       u32 outlen;
+       int ret;
+       u8 subopcode;
+       Scsi_Cmnd *scsicmd;
+       struct Scsi_Host *shpnt;
+       char *uaddr;
+       struct uioctl_t *uioc;
+       dma_addr_t      dma_addr;
+       u32             length;
+       mega_host_config *megacfg = NULL;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)        /* 0x020400 */
+       struct pci_dev pdev;
+       struct pci_dev *pdevp = &pdev;
+#else
+       char *pdevp = NULL;
+#endif
+       IO_LOCK_T;
+
+       if (!inode || !(dev = inode->i_rdev))
+               return -EINVAL;
+
+       if (_IOC_TYPE (cmd) != MEGAIOC_MAGIC)
+               return (-EINVAL);
+
+       /*
+        * Get the user ioctl structure
+        */
+       ret = verify_area (VERIFY_WRITE, (char *) arg, sizeof (struct uioctl_t));
+
+       if (ret)
+               return ret;
+
+       if(copy_from_user (&ioc, (char *) arg, sizeof (struct uioctl_t)))
+               return -EFAULT;
+
+       /*
+        * The first call the applications should make is to find out the
+        * number of controllers in the system. The next logical call should
+        * be for getting the list of controllers in the system as detected
+        * by the driver.
+        */
+
+       /*
+        * Get the opcode and subopcode for the commands
+        */
+       opcode = ioc.ui.fcs.opcode;
+       subopcode = ioc.ui.fcs.subopcode;
+
+       switch (opcode) {
+       case M_RD_DRIVER_IOCTL_INTERFACE:
+               switch (subopcode) {
+               case MEGAIOC_QDRVRVER:  /* Query driver version */
+                       put_user (driver_ver, (u32 *) ioc.data);
+                       return 0;
+
+               case MEGAIOC_QNADAP:    /* Get # of adapters */
+                       put_user (nadap, (int *) ioc.data);
+                       return nadap;
+
+               case MEGAIOC_QADAPINFO: /* Get adapter information */
+                       /*
+                        * which adapter?
+                        */
+                       adapno = ioc.ui.fcs.adapno;
+
+                       /*
+                        * The adapter numbers do not start with 0, at least in
+                        * the user space. This is just to make sure, 0 is not the
+                        * default value which will refer to adapter 1. So the
+                        * user needs to make use of macros MKADAP() and GETADAP()
+                        * (See megaraid.h) while making ioctl() call.
+                        */
+                       adapno = GETADAP (adapno);
+
+                       if (adapno >= numCtlrs)
+                               return (-ENODEV);
+
+                       ret = verify_area (VERIFY_WRITE,
+                                          ioc.data,
+                                          sizeof (struct mcontroller));
+                       if (ret)
+                               return ret;
+
+                       /*
+                        * Copy struct mcontroller to user area
+                        */
+                       if (copy_to_user (ioc.data,
+                                     mcontroller + adapno,
+                                     sizeof (struct mcontroller)))
+                                     return -EFAULT;
+                       return 0;
+
+               default:
+                       return (-EINVAL);
+
+               }               /* inner switch */
+               break;
+
+       case M_RD_IOCTL_CMD_NEW:
+
+               /*
+                * Deletion of logical drives is only handled in 0x80 commands
+                */
+               if( ioc.mbox[0] == FC_DEL_LOGDRV && ioc.mbox[2] == OP_DEL_LOGDRV ) {
+                       return -EINVAL;
+               }
+
+               /* which adapter?  */
+               adapno = ioc.ui.fcs.adapno;
+
+               /* See comment above: MEGAIOC_QADAPINFO */
+               adapno = GETADAP(adapno);
+
+               if (adapno >= numCtlrs)
+                       return(-ENODEV);
+
+               length = ioc.ui.fcs.length;
+
+               /* Check for zero length buffer or very large buffers */
+               if( !length || length > 32*1024 )
+                       return -EINVAL;
+
+               /* save the user address */
+               uaddr = ioc.ui.fcs.buffer;
+
+               /*
+                * For M_RD_IOCTL_CMD_NEW commands, the fields outlen and inlen of
+                * uioctl_t structure are treated as flags. If outlen is 1, the
+                * data is transferred from the device and if inlen is 1, the data
+                * is transferred to the device.
+                */
+               outlen = ioc.outlen;
+               inlen = ioc.inlen;
+
+               if(outlen) {
+                       ret = verify_area(VERIFY_WRITE, (char *)ioc.ui.fcs.buffer, length);
+                       if (ret) return ret;
+               }
+               if(inlen) {
+                       ret = verify_area(VERIFY_READ, (char *) ioc.ui.fcs.buffer, length);
+                       if (ret) return ret;
+               }
+
+               /*
+                * Find this host
+                */
+               for( shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next ) {
+                       if( shpnt->hostdata == (unsigned long *)megaCtlrs[adapno] ) {
+                               megacfg = (mega_host_config *)shpnt->hostdata;
+                               break;
+                       }
+               }
+               if(shpnt == NULL)  return -ENODEV;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+               scsicmd = (Scsi_Cmnd *)kmalloc(sizeof(Scsi_Cmnd), GFP_KERNEL|GFP_DMA);
+#else
+               scsicmd = (Scsi_Cmnd *)scsi_init_malloc(sizeof(Scsi_Cmnd),
+                                                         GFP_ATOMIC | GFP_DMA);
+#endif
+               if(scsicmd == NULL) return -ENOMEM;
+
+               memset(scsicmd, 0, sizeof(Scsi_Cmnd));
+               scsicmd->host = shpnt;
+
+               if( outlen || inlen ) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+                       pdevp = &pdev;
+                       memcpy(pdevp, megacfg->dev, sizeof(struct pci_dev));
+                       pdevp->dma_mask = 0xffffffff;
+#else
+                       pdevp = NULL;
+#endif
+                       kvaddr = dma_alloc_consistent(pdevp, length, &dma_addr);
+
+                       if( kvaddr == NULL ) {
+                               printk(KERN_WARNING "megaraid:allocation failed\n");
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)        /*0x20400 */
+                               kfree(scsicmd);
+#else
+                               scsi_init_free((char *)scsicmd, sizeof(Scsi_Cmnd));
+#endif
+                               return -ENOMEM;
+                       }
+
+                       ioc.ui.fcs.buffer = kvaddr;
+
+                       if (inlen) {
+                               /* copyin the user data */
+                               copy_from_user(kvaddr, (char *)uaddr, length );
+                       }
+               }
+
+               scsicmd->cmnd[0] = MEGADEVIOC;
+               scsicmd->request_buffer = (void *)&ioc;
+
+#if XENO_KILLED
+               init_MUTEX_LOCKED(&mimd_ioctl_sem);
+#endif
+
+               IO_LOCK;
+               megaraid_queue(scsicmd, megadev_ioctl_done);
+
+               IO_UNLOCK;
+#if XENO_KILLED
+               down(&mimd_ioctl_sem);
+#endif
+               if( !scsicmd->result && outlen ) {
+                       if (copy_to_user(uaddr, kvaddr, length))
+                               return -EFAULT;
+               }
+
+               /*
+                * copyout the result
+                */
+               uioc = (struct uioctl_t *)arg;
+
+               if( ioc.mbox[0] == MEGA_MBOXCMD_PASSTHRU ) {
+                       put_user( scsicmd->result, &uioc->pthru.scsistatus );
+                       if (copy_to_user( uioc->pthru.reqsensearea, scsicmd->sense_buffer,
+                                                         MAX_REQ_SENSE_LEN ));
+                               ret= -EFAULT;
+               } else {
+                       put_user(1, &uioc->mbox[16]);   /* numstatus */
+                       /* status */
+                       put_user (scsicmd->result, &uioc->mbox[17]);
+               }
+
+               if (kvaddr) {
+                       dma_free_consistent(pdevp, length, kvaddr, dma_addr);
+               }
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)        /*0x20400 */
+               kfree (scsicmd);
+#else
+               scsi_init_free((char *)scsicmd, sizeof(Scsi_Cmnd));
+#endif
+
+               /* restore the user address */
+               ioc.ui.fcs.buffer = uaddr;
+
+               return ret;
+
+       case M_RD_IOCTL_CMD:
+               /* which adapter?  */
+               adapno = ioc.ui.fcs.adapno;
+
+               /* See comment above: MEGAIOC_QADAPINFO */
+               adapno = GETADAP (adapno);
+
+               if (adapno >= numCtlrs)
+                       return (-ENODEV);
+
+               /* save the user address */
+               uaddr = ioc.data;
+               outlen = ioc.outlen;
+               inlen = ioc.inlen;
+
+               if ((outlen >= IOCTL_MAX_DATALEN) || (inlen >= IOCTL_MAX_DATALEN))
+                       return (-EINVAL);
+
+               if (outlen) {
+                       ret = verify_area (VERIFY_WRITE, ioc.data, outlen);
+                       if (ret) return ret;
+               }
+               if (inlen) {
+                       ret = verify_area (VERIFY_READ, ioc.data, inlen);
+                       if (ret) return ret;
+               }
+
+               /*
+                * Find this host
+                */
+               for( shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next ) {
+                       if( shpnt->hostdata == (unsigned long *)megaCtlrs[adapno] ) {
+                               megacfg = (mega_host_config *)shpnt->hostdata;
+                               break;
+                       }
+               }
+               if(shpnt == NULL)  return -ENODEV;
+
+               /*
+                * ioctls for deleting logical drives is a special case, so check
+                * for it first
+                */
+               if( ioc.mbox[0] == FC_DEL_LOGDRV && ioc.mbox[2] == OP_DEL_LOGDRV ) {
+
+                       if( !megacfg->support_random_del ) {
+                               printk("megaraid: logdrv delete on non supporting f/w.\n");
+                               return -EINVAL;
+                       }
+
+                       uioc = (struct uioctl_t *)arg;
+
+                       ret = mega_del_logdrv(megacfg, ioc.mbox[3]);
+
+                       put_user(1, &uioc->mbox[16]);   /* numstatus */
+                       put_user(ret, &uioc->mbox[17]); /* status */
+
+                       /* if deletion failed, let the user know by failing ioctl */
+                       return ret;
+               }
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+               scsicmd = (Scsi_Cmnd *)kmalloc(sizeof(Scsi_Cmnd), GFP_KERNEL|GFP_DMA);
+#else
+               scsicmd = (Scsi_Cmnd *)scsi_init_malloc(sizeof(Scsi_Cmnd),
+                                                         GFP_ATOMIC | GFP_DMA);
+#endif
+               if(scsicmd == NULL) return -ENOMEM;
+
+               memset(scsicmd, 0, sizeof(Scsi_Cmnd));
+               scsicmd->host = shpnt;
+
+               if (outlen || inlen) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+                       pdevp = &pdev;
+                       memcpy(pdevp, megacfg->dev, sizeof(struct pci_dev));
+                       pdevp->dma_mask = 0xffffffff;
+#else
+                       pdevp = NULL;
+#endif
+                       /*
+                        * Allocate a page of kernel space.
+                        */
+                       kvaddr = dma_alloc_consistent(pdevp, PAGE_SIZE, &dma_addr);
+
+                       if( kvaddr == NULL ) {
+                               printk (KERN_WARNING "megaraid:allocation failed\n");
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)        /*0x20400 */
+                               kfree(scsicmd);
+#else
+                               scsi_init_free((char *)scsicmd, sizeof(Scsi_Cmnd));
+#endif
+                               return -ENOMEM;
+                       }
+
+                       ioc.data = kvaddr;
+
+                       if (inlen) {
+                               if (ioc.mbox[0] == MEGA_MBOXCMD_PASSTHRU) {
+                                       /* copyin the user data */
+                                       copy_from_user (kvaddr, uaddr, ioc.pthru.dataxferlen);
+                               } else {
+                                       copy_from_user (kvaddr, uaddr, inlen);
+                               }
+                       }
+               }
+
+               scsicmd->cmnd[0] = MEGADEVIOC;
+               scsicmd->request_buffer = (void *) &ioc;
+
+#if XENO_KILLED
+               init_MUTEX_LOCKED (&mimd_ioctl_sem);
+#endif
+
+               IO_LOCK;
+               megaraid_queue (scsicmd, megadev_ioctl_done);
+
+               IO_UNLOCK;
+#if XENO_KILLED
+               down (&mimd_ioctl_sem);
+#endif
+
+               if (!scsicmd->result && outlen) {
+                       if (ioc.mbox[0] == MEGA_MBOXCMD_PASSTHRU) {
+                               if (copy_to_user (uaddr, kvaddr, ioc.pthru.dataxferlen))        
+                                       ret = -EFAULT;
+                       } else {
+                               if (copy_to_user (uaddr, kvaddr, outlen)) 
+                                       ret = -EFAULT;
+                       }
+               }
+
+               /*
+                * copyout the result
+                */
+               uioc = (struct uioctl_t *) arg;
+
+               if (ioc.mbox[0] == MEGA_MBOXCMD_PASSTHRU) {
+                       put_user (scsicmd->result, &uioc->pthru.scsistatus);
+
+                       /*
+                        * If scsicmd->result is 0x02 (CHECK CONDITION) then copy the
+                        * SCSI sense data into user area
+                        */
+                       if (copy_to_user( uioc->pthru.reqsensearea, scsicmd->sense_buffer,
+                                                         MAX_REQ_SENSE_LEN ))
+                               ret = -EFAULT;
+                                                       
+               } else {
+                       put_user (1, &uioc->mbox[16]);  /* numstatus */
+                       put_user (scsicmd->result, &uioc->mbox[17]); /* status */
+               }
+
+               if (kvaddr) {
+                       dma_free_consistent(pdevp, PAGE_SIZE, kvaddr, dma_addr );
+               }
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+               kfree (scsicmd);
+#else
+               scsi_init_free((char *)scsicmd, sizeof(Scsi_Cmnd));
+#endif
+
+               /* restore user pointer */
+               ioc.data = uaddr;
+
+               return ret;
+
+       default:
+               return (-EINVAL);
+
+       }/* Outer switch */
+
+       return 0;
+}
+
+static void
+megadev_ioctl_done(Scsi_Cmnd *sc)
+{
+#if XENO_KILLED
+       up (&mimd_ioctl_sem);
+#endif
+}
+
+static mega_scb *
+megadev_doioctl (mega_host_config * megacfg, Scsi_Cmnd * sc)
+{
+       u8 cmd;
+       struct uioctl_t *ioc = NULL;
+       mega_mailbox *mbox = NULL;
+       mega_ioctl_mbox *mboxioc = NULL;
+       struct mbox_passthru *mboxpthru = NULL;
+       mega_scb *scb = NULL;
+       mega_passthru *pthru = NULL;
+
+       if ((scb = mega_allocateSCB (megacfg, sc)) == NULL) {
+               sc->result = (DID_ERROR << 16);
+               callDone (sc);
+               return NULL;
+       }
+
+       ioc = (struct uioctl_t *) sc->request_buffer;
+
+       memcpy (scb->mboxData, ioc->mbox, sizeof (scb->mboxData));
+
+       /* The generic mailbox */
+       mbox = (mega_mailbox *) ioc->mbox;
+
+       /*
+        * Get the user command
+        */
+       cmd = ioc->mbox[0];
+
+       switch (cmd) {
+       case MEGA_MBOXCMD_PASSTHRU:
+               /*
+                  * prepare the SCB with information from the user ioctl structure
+                */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+               pthru = scb->pthru;
+#else
+               pthru = &scb->pthru;
+#endif
+               memcpy (pthru, &ioc->pthru, sizeof (mega_passthru));
+               mboxpthru = (struct mbox_passthru *) scb->mboxData;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+               if (megacfg->flag & BOARD_64BIT) {
+                       /* This is just a sample with one element 
+                          * This if executes onlu on 2.4 kernels
+                        */
+                       mboxpthru->dataxferaddr = scb->dma_passthruhandle64;
+                       scb->sg64List[0].address =
+                           pci_map_single (megacfg->dev,
+                                           ioc->data,
+                                           4096, PCI_DMA_BIDIRECTIONAL);
+                       scb->sg64List[0].length = 4096; // TODO: Check this
+                       pthru->dataxferaddr = scb->dma_sghandle64;
+                       pthru->numsgelements = 1;
+                       mboxpthru->cmd = MEGA_MBOXCMD_PASSTHRU64;
+               } else {
+                       mboxpthru->dataxferaddr = scb->dma_passthruhandle64;
+                       pthru->dataxferaddr =
+                           pci_map_single (megacfg->dev,
+                                           ioc->data,
+                                           4096, PCI_DMA_BIDIRECTIONAL);
+                       pthru->numsgelements = 0;
+               }
+
+#else
+               {
+                       mboxpthru->dataxferaddr = virt_to_bus (&scb->pthru);
+                       pthru->dataxferaddr = virt_to_bus (ioc->data);
+                       pthru->numsgelements = 0;
+               }
+#endif
+
+               pthru->reqsenselen = 14;
+               break;
+
+       default:                /* Normal command */
+               mboxioc = (mega_ioctl_mbox *) scb->mboxData;
+
+               if (ioc->ui.fcs.opcode == M_RD_IOCTL_CMD_NEW) {
+                       scb->buff_ptr = ioc->ui.fcs.buffer;
+                       scb->iDataSize = ioc->ui.fcs.length;
+               } else {
+                       scb->buff_ptr = ioc->data;
+                       scb->iDataSize = 4096;  // TODO:check it
+               }
+
+               set_mbox_xfer_addr (megacfg, scb, mboxioc, FROMTO_DEVICE);
+               mboxioc->numsgelements = 0;
+               break;
+       }
+
+       return scb;
+}
+
+static int
+megadev_close (struct inode *inode, struct file *filep)
+{
+#ifdef MODULE
+       MOD_DEC_USE_COUNT;
+#endif
+       return 0;
+}
+
+
+static int
+mega_support_ext_cdb(mega_host_config *this_hba)
+{
+       mega_mailbox *mboxpnt;
+       unsigned char mbox[16];
+       int ret;
+
+       mboxpnt = (mega_mailbox *) mbox;
+
+       memset(mbox, 0, sizeof (mbox));
+       /*
+        * issue command to find out if controller supports extended CDBs.
+        */
+       mbox[0] = 0xA4;
+       mbox[2] = 0x16;
+
+       ret = megaIssueCmd(this_hba, mbox, NULL, 0);
+
+       return !ret;
+}
+
+
+/*
+ * Find out if this controller supports random deletion and addition of
+ * logical drives
+ */
+static int
+mega_support_random_del(mega_host_config *this_hba)
+{
+#if XENO_KILLED
+       mega_mailbox *mboxpnt;
+       unsigned char mbox[16];
+       int ret;
+
+       mboxpnt = (mega_mailbox *)mbox;
+
+       memset(mbox, 0, sizeof(mbox));
+
+       /*
+        * issue command
+        */
+       mbox[0] = FC_DEL_LOGDRV;
+       mbox[2] = OP_SUP_DEL_LOGDRV;
+
+       ret = megaIssueCmd(this_hba, mbox, NULL, 0);
+
+       return !ret;
+#endif
+       return 0; // no support for random deletions
+}
+
+static int
+mega_del_logdrv(mega_host_config *this_hba, int logdrv)
+{
+  return -ENOSYS;
+#if XENO_KILLED
+       int             rval;
+       IO_LOCK_T;
+       DECLARE_WAIT_QUEUE_HEAD(wq);
+       mega_scb        *scbp;
+
+       /*
+        * Stop sending commands to the controller, queue them internally.
+        * When deletion is complete, ISR will flush the queue.
+        */
+       IO_LOCK;
+       this_hba->quiescent = 1;
+       IO_UNLOCK;
+
+       while( this_hba->qPcnt ) {
+                       sleep_on_timeout( &wq, 1*HZ );  /* sleep for 1s */
+       }
+       rval = mega_do_del_logdrv(this_hba, logdrv);
+
+       IO_LOCK;
+       /*
+        * Attach the internal queue to the pending queue
+        */
+       if( this_hba->qPendingH == NULL ) {
+               /*
+                * If pending queue head is null, make internal queue as
+                * pending queue
+                */
+               this_hba->qPendingH = this_hba->int_qh;
+               this_hba->qPendingT = this_hba->int_qt;
+               this_hba->qPcnt = this_hba->int_qlen;
+       }
+       else {
+               /*
+                * Append pending queue to internal queue
+                */
+               if( this_hba->int_qt ) {
+                       this_hba->int_qt->next = this_hba->qPendingH;
+
+                       this_hba->qPendingH = this_hba->int_qh;
+                       this_hba->qPcnt += this_hba->int_qlen;
+               }
+       }
+
+       this_hba->int_qh = this_hba->int_qt = NULL;
+       this_hba->int_qlen = 0;
+
+       /*
+        * If delete operation was successful, add 0x80 to the logical drive
+        * ids for commands in the pending queue.
+        */
+       if( this_hba->read_ldidmap) {
+               for( scbp = this_hba->qPendingH; scbp; scbp = scbp->next ) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+                       if( scbp->pthru->logdrv < 0x80 )
+                               scbp->pthru->logdrv += 0x80;
+#else
+                       if( scbp->pthru.logdrv < 0x80 )
+                               scbp->pthru.logdrv += 0x80;
+#endif
+               }
+       }
+       this_hba->quiescent = 0;
+
+       IO_UNLOCK;
+
+       return rval;
+#endif
+}
+
+
+static int
+mega_do_del_logdrv(mega_host_config *this_hba, int logdrv)
+{
+       mega_mailbox *mboxpnt;
+       unsigned char mbox[16];
+       int rval;
+
+       mboxpnt = (mega_mailbox *)mbox;
+
+       memset(mbox, 0, sizeof(mbox));
+
+       mbox[0] = FC_DEL_LOGDRV;
+       mbox[2] = OP_DEL_LOGDRV;
+       mbox[3] = logdrv;
+
+       rval = megaIssueCmd(this_hba, mbox, NULL, 0);
+
+       /* log this event */
+       if( rval != 0 ) {
+               printk("megaraid: Attempt to delete logical drive %d failed.",
+                               logdrv);
+               return rval;
+       }
+
+       printk("megaraid: logical drive %d deleted.\n", logdrv);
+
+       /*
+        * After deleting first logical drive, the logical drives must be
+        * addressed by adding 0x80 to the logical drive id.
+        */
+       this_hba->read_ldidmap = 1;
+
+       return rval;
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
+void *
+dma_alloc_consistent(void *dev, size_t size, dma_addr_t *dma_addr)
+{
+       void    *_tv;
+       int             npages;
+       int             order = 0;
+
+       /*
+        * How many pages application needs
+        */
+       npages = size / PAGE_SIZE;
+
+       /* Do we need one more page */
+       if(size % PAGE_SIZE)
+               npages++;
+
+       order = mega_get_order(npages);
+
+       _tv = (void *)__get_free_pages(GFP_DMA, order);
+
+       if( _tv != NULL ) {
+               memset(_tv, 0, size);
+               *(dma_addr) = virt_to_bus(_tv);
+       }
+
+       return _tv;
+}
+
+/*
+ * int mega_get_order(int)
+ *
+ * returns the order to be used as 2nd argument to __get_free_pages() - which
+ * return pages equal to pow(2, order) - AM
+ */
+int
+mega_get_order(int n)
+{
+       int             i = 0;
+
+       while( pow_2(i++) < n )
+               ; /* null statement */
+
+       return i-1;
+}
+
+/*
+ * int pow_2(int)
+ *
+ * calculates pow(2, i)
+ */
+int
+pow_2(int i)
+{
+       unsigned int    v = 1;
+       
+       while(i--)
+               v <<= 1;
+
+       return v;
+}
+
+void
+dma_free_consistent(void *dev, size_t size, void *vaddr, dma_addr_t dma_addr)
+{
+       int             npages;
+       int             order = 0;
+
+       npages = size / PAGE_SIZE;
+
+       if(size % PAGE_SIZE)
+               npages++;
+
+       if (npages == 1)
+               order = 0;
+       else if (npages == 2)
+               order = 1;
+       else if (npages <= 4)
+               order = 2;
+       else
+               order = 3;
+
+       free_pages((unsigned long)vaddr, order);
+
+}
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+static
+#endif                         /* LINUX VERSION 2.4.XX */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) || defined(MODULE)
+Scsi_Host_Template driver_template = MEGARAID;
+
+#include "scsi_module.c.inc"
+#endif                         /* LINUX VERSION 2.4.XX || MODULE */
+
+/* vi: set ts=4: */
diff --git a/xen/drivers/scsi/megaraid.h b/xen/drivers/scsi/megaraid.h
new file mode 100644 (file)
index 0000000..a84a7ac
--- /dev/null
@@ -0,0 +1,1040 @@
+#ifndef __MEGARAID_H__
+#define __MEGARAID_H__
+
+#include <xeno/version.h>
+
+/*
+ * For state flag. Do not use LSB(8 bits) which are
+ * reserved for storing info about channels.
+ */
+#define IN_ISR                 0x80000000L
+#define IN_ABORT               0x40000000L
+#define IN_RESET               0x20000000L
+#define IN_QUEUE               0x10000000L
+#define BOARD_QUARTZ   0x08000000L
+#define BOARD_40LD             0x04000000L
+#define BOARD_64BIT            0x02000000L
+
+#define SCB_FREE     0x0
+#define SCB_ACTIVE   0x1
+#define SCB_WAITQ    0x2
+#define SCB_ISSUED   0x3
+#define SCB_COMPLETE 0x4
+#define SCB_ABORTED  0x5
+#define SCB_RESET    0x6
+
+#define M_RD_CRLFSTR                   "\n"
+#define M_RD_IOCTL_CMD                 0x80
+#define M_RD_IOCTL_CMD_NEW             0x81
+#define M_RD_DRIVER_IOCTL_INTERFACE    0x82
+
+#define MEGARAID_VERSION "v1.18d (Release Date: Wed Aug  7 18:51:51 EDT 2002)\n"
+
+#define MEGARAID_IOCTL_VERSION         114
+
+/* Methods */
+#define GET_DRIVER_INFO                0x1
+
+#define MEGA_CMD_TIMEOUT               10
+
+/* Feel free to fiddle with these.. max values are:
+   SGLIST     0..26
+   COMMANDS   0..253
+   CMDPERLUN  0..63
+*/
+
+#define MAX_SGLIST             0x1A
+#define MAX_COMMANDS           127
+#define MAX_CMD_PER_LUN                63
+#define MAX_FIRMWARE_STATUS     46
+
+#define MAX_LOGICAL_DRIVES      8
+#define MAX_CHANNEL            5
+#define MAX_TARGET             15
+#define MAX_PHYSICAL_DRIVES     MAX_CHANNEL*MAX_TARGET
+
+#define INQUIRY_DATA_SIZE       0x24
+#define MAX_CDB_LEN                    0x0A
+#define MAX_REQ_SENSE_LEN       0x20
+
+#define INTR_VALID             0x40
+
+/* Direction Macros for MBOX Data direction */
+#define TO_DEVICE              0x0
+#define FROM_DEVICE            0x1
+#define FROMTO_DEVICE          0x2
+
+/* Mailbox commands */
+#define MEGA_MBOXCMD_LREAD             0x01
+#define MEGA_MBOXCMD_LWRITE            0x02
+#define MEGA_MBOXCMD_LREAD64           0xA7
+#define MEGA_MBOXCMD_LWRITE64          0xA8
+#define MEGA_MBOXCMD_PASSTHRU          0x03
+#define MEGA_MBOXCMD_EXTPASSTHRU       0xE3
+#define MEGA_MBOXCMD_PASSTHRU64                0xC3
+#define MEGA_MBOXCMD_ADAPTERINQ                0x05
+
+
+/* Offsets into Mailbox */
+#define COMMAND_PORT           0x00
+#define COMMAND_ID_PORT        0x01
+#define SG_LIST_PORT0          0x08
+#define SG_LIST_PORT1          0x09
+#define SG_LIST_PORT2          0x0a
+#define SG_LIST_PORT3          0x0b
+#define SG_ELEMENT_PORT        0x0d
+#define NO_FIRED_PORT          0x0f
+
+/* I/O Port offsets */
+#define I_CMD_PORT             0x00
+#define I_ACK_PORT             0x00
+#define I_TOGGLE_PORT          0x01
+#define INTR_PORT              0x0a
+
+#define MAILBOX_SIZE           (sizeof(mega_mailbox)-16)
+#define MBOX_BUSY_PORT         0x00
+#define MBOX_PORT0             0x04
+#define MBOX_PORT1             0x05
+#define MBOX_PORT2             0x06
+#define MBOX_PORT3             0x07
+#define ENABLE_MBOX_REGION     0x0B
+
+/* I/O Port Values */
+#define ISSUE_BYTE             0x10
+#define ACK_BYTE               0x08
+#define ENABLE_INTR_BYTE       0xc0
+#define DISABLE_INTR_BYTE      0x00
+#define VALID_INTR_BYTE        0x40
+#define MBOX_BUSY_BYTE         0x10
+#define ENABLE_MBOX_BYTE       0x00
+
+/* Setup some port macros here */
+#define WRITE_MAILBOX(base,offset,value)       *(base+offset)=value
+#define READ_MAILBOX(base,offset)              *(base+offset)
+
+#define WRITE_PORT(base,offset,value)          outb_p(value,base+offset)
+#define READ_PORT(base,offset)                 inb_p(base+offset)
+
+#define ISSUE_COMMAND(base)    WRITE_PORT(base,I_CMD_PORT,ISSUE_BYTE)
+#define CLEAR_INTR(base)       WRITE_PORT(base,I_ACK_PORT,ACK_BYTE)
+#define ENABLE_INTR(base)      WRITE_PORT(base,I_TOGGLE_PORT,ENABLE_INTR_BYTE)
+#define DISABLE_INTR(base)     WRITE_PORT(base,I_TOGGLE_PORT,DISABLE_INTR_BYTE)
+
+#ifndef PCI_VENDOR_ID_LSI_LOGIC
+#define PCI_VENDOR_ID_LSI_LOGIC                0x1000
+#endif
+
+/* Define AMI's PCI codes */
+#ifndef PCI_VENDOR_ID_AMI
+#define PCI_VENDOR_ID_AMI              0x101E
+#endif
+
+#ifndef PCI_DEVICE_ID_AMI_MEGARAID
+#define PCI_DEVICE_ID_AMI_MEGARAID     0x9010
+#endif
+
+#ifndef PCI_DEVICE_ID_AMI_MEGARAID2
+#define PCI_DEVICE_ID_AMI_MEGARAID2    0x9060
+#endif
+
+#ifndef PCI_DEVICE_ID_AMI_MEGARAID3
+#define PCI_DEVICE_ID_AMI_MEGARAID3    0x1960
+#endif
+
+#define PCI_VENDOR_ID_DISCOVERY                0x1028
+#define PCI_DEVICE_ID_DISCOVERY                0x000E
+
+#define PCI_VENDOR_ID_PERC4_DI_YSTONE  0x1028
+#define PCI_DEVICE_ID_PERC4_DI_YSTONE  0x000F
+
+#define PCI_VENDOR_ID_PERC4_QC_VERDE   0x1000
+#define PCI_DEVICE_ID_PERC4_QC_VERDE   0x0407
+
+/* Special Adapter Commands */
+#define FW_FIRE_WRITE          0x2C
+#define FW_FIRE_FLASH          0x2D
+
+#define FC_NEW_CONFIG                  0xA1
+#define DCMD_FC_CMD                    0xA1
+#define DCMD_FC_PROCEED                        0x02
+#define DCMD_DELETE_LOGDRV             0x03
+#define DCMD_FC_READ_NVRAM_CONFIG      0x04
+#define DCMD_FC_READ_NVRAM_CONFIG_64           0xC0
+#define DCMD_FC_READ_FINAL_CONFIG      0x05
+#define DCMD_GET_DISK_CONFIG           0x06
+#define DCMD_GET_DISK_CONFIG_64                0xC2
+#define DCMD_CHANGE_LDNO               0x07
+#define DCMD_COMPACT_CONFIG            0x08
+#define DCMD_DELETE_DRIVEGROUP         0x09
+#define DCMD_GET_LOOPID_INFO           0x0A
+#define DCMD_CHANGE_LOOPID             0x0B
+#define DCMD_GET_NUM_SCSI_CHANS        0x0C
+#define DCMD_WRITE_CONFIG              0x0D
+#define DCMD_WRITE_CONFIG_64                   0xC1
+
+#define NC_SUBOP_PRODUCT_INFO          0x0E
+#define NC_SUBOP_ENQUIRY3              0x0F
+#define ENQ3_GET_SOLICITED_NOTIFY_ONLY  0x01
+#define ENQ3_GET_SOLICITED_FULL                0x02
+#define ENQ3_GET_UNSOLICITED           0x03
+
+#define PCI_CONF_BASE_ADDR_OFFSET      0x10
+#define PCI_CONF_IRQ_OFFSET            0x3c
+#define PCI_CONF_AMISIG                        0xa0
+#define PCI_CONF_AMISIG64              0xa4
+
+/* Sub-System Vendor ID sorted on alphabetical order*/
+#define LSI_SUBSYS_ID                  0x1000
+#define        AMI_SUBSYS_ID                   0x101E
+#define DELL_SUBSYS_ID                 0x1028
+#define        HP_SUBSYS_ID                    0x103C
+
+#define AMI_SIGNATURE                  0x3344
+#define AMI_SIGNATURE_471              0xCCCC
+#define AMI_64BIT_SIGNATURE            0x0299
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0) /*0x20100 */
+#define MEGARAID \
+  { NULL,                              /* Next                         */\
+    NULL,                              /* Usage Count Pointer          */\
+    NULL,                              /* proc Directory Entry         */\
+    megaraid_proc_info,                        /* proc Info Function           */\
+    "MegaRAID",                                /* Driver Name                  */\
+    megaraid_detect,                   /* Detect Host Adapter          */\
+    megaraid_release,                  /* Release Host Adapter         */\
+    megaraid_info,                     /* Driver Info Function         */\
+    megaraid_command,                  /* Command Function             */\
+    megaraid_queue,                    /* Queue Command Function       */\
+    megaraid_abort,                    /* Abort Command Function       */\
+    megaraid_reset,                    /* Reset Command Function       */\
+    NULL,                              /* Slave Attach Function        */\
+    megaraid_biosparam,                        /* Disk BIOS Parameters         */\
+    MAX_COMMANDS,                      /* # of cmds that can be\
+                                       outstanding at any time         */\
+    7,                                 /* HBA Target ID                */\
+    MAX_SGLIST,                                /* Scatter/Gather Table Size    */\
+    MAX_CMD_PER_LUN,                   /* SCSI Commands per LUN        */\
+    0,                                 /* Present                      */\
+    0,                                 /* Default Unchecked ISA DMA    */\
+    ENABLE_CLUSTERING }                        /* Enable Clustering            */
+#else
+#define MEGARAID \
+  {\
+    name:              "MegaRAID",             /* Driver Name                  */\
+    detect:            megaraid_detect,        /* Detect Host Adapter          */\
+    release:           megaraid_release,       /* Release Host Adapter         */\
+    info:              megaraid_info,          /* Driver Info Function         */\
+    command:            NULL, /* XEN KILLED */\
+    queuecommand:      megaraid_queue,         /* Queue Command Function       */\
+    abort:             megaraid_abort,         /* Abort Command Function       */\
+    reset:             megaraid_reset,         /* Reset Command Function       */\
+    bios_param:        megaraid_biosparam,     /* Disk BIOS Parameters         */\
+    can_queue:         MAX_COMMANDS,           /* Can Queue                    */\
+    this_id:           7,                      /* HBA Target ID                */\
+    sg_tablesize:      MAX_SGLIST,             /* Scatter/Gather Table Size    */\
+    cmd_per_lun:       MAX_CMD_PER_LUN,        /* SCSI Commands per LUN        */\
+    present:           0,                      /* Present                      */\
+    unchecked_isa_dma: 0,                      /* Default Unchecked ISA DMA    */\
+    use_clustering:    ENABLE_CLUSTERING,      /* Enable Clustering            */\
+  }
+#endif
+// XENO: REMOVED     command:          megaraid_command,       /* Command Function             */
+// XENO: REMOVED     proc_info:                megaraid_proc_info,     /* /proc driver info            */
+// XENO: REMOVED       highmem_io:             1, /* enable HIGHMEM I/O */ 
+
+
+/***********************************************************************
+ * Structure Declarations for the Firmware supporting 40 Logical Drives
+ * and 256 Physical Drives.
+ ***********************************************************************/
+
+#define FC_MAX_LOGICAL_DRIVES          40
+#define FC_MAX_LOG_DEVICES             FC_MAX_LOGICAL_DRIVES
+#define FC_MAX_SPAN_DEPTH              8
+#define FC_MAX_ROW_SIZE                        32
+
+#define FC_MAX_CHANNELS                        16
+#define FC_MAX_TARGETS_PER_CHANNEL     16
+#define FC_MAX_PHYSICAL_DEVICES        256
+
+/********************************************
+ * PRODUCT_INFO
+ ********************************************/
+
+#define SIG_40LOG_32STR_8SPN  0x00282008
+
+/*
+ * Utilities declare this strcture size as 1024 bytes. So more fields can
+ * be added in future.
+ */
+
+struct MRaidProductInfo {
+       u32 DataSize;           /* current size in bytes (not including resvd) */
+       u32 ConfigSignature;
+       /* Current value is 0x00282008
+        * 0x28=MAX_LOGICAL_DRIVES,
+        * 0x20=Number of stripes and
+        * 0x08=Number of spans */
+       u8 FwVer[16];           /* printable ASCI string */
+       u8 BiosVer[16];         /* printable ASCI string */
+       u8 ProductName[80];     /* printable ASCI string */
+
+       u8 MaxConcCmds;         /* Max. concurrent commands supported */
+       u8 SCSIChanPresent;     /* Number of SCSI Channels detected */
+       u8 FCLoopPresent;       /* Number of Fibre Loops detected */
+       u8 memType;             /* EDO, FPM, SDRAM etc */
+
+       u32 signature;
+       u16 DramSize;           /* In terms of MB */
+       u16 subSystemID;
+
+       u16 subSystemVendorID;
+       u8 numNotifyCounters;
+       u8 pad1k[889];          /* 135 + 889 resvd = 1024 total size */
+} __attribute__ ((packed));
+typedef struct MRaidProductInfo megaRaidProductInfo;
+
+/********************************************
+ * Standard ENQUIRY
+ ********************************************/
+struct FC_ADP_INFO {
+       u8 MaxConcCmds;         /* Max. concurrent commands supported. */
+       u8 RbldRate;            /* Rebuild Rate. Varies from 0%-100% */
+       u8 MaxTargPerChan;      /* Max. Targets supported per chan. */
+       u8 ChanPresent;         /* No. of Chans present on this adapter. */
+       u8 FwVer[4];            /* Firmware version. */
+       u16 AgeOfFlash;         /* No. of times FW has been downloaded. */
+       u8 ChipSetValue;        /* Contents of 0xC0000832 */
+       u8 DramSize;            /* In terms of MB */
+       u8 CacheFlushInterval;  /* In terms of Seconds */
+       u8 BiosVersion[4];
+       u8 BoardType;
+       u8 sense_alert;
+       u8 write_config_count;  /* Increase with evry configuration change */
+       u8 drive_inserted_count;/* Increase with every drive inserted */
+       u8 inserted_drive;      /* Channel: Id of inserted drive */
+       u8 battery_status;
+       /*
+          BIT 0 : battery module missing
+          BIT 1 : VBAD
+          BIT 2 : temp high
+          BIT 3 : battery pack missing
+          BIT 4,5 : 00 - charge complete
+          01 - fast charge in prog
+          10 - fast charge fail
+          11 - undefined
+          BIt 6 : counter > 1000
+          Bit 7 : undefined
+        */
+       u8 dec_fault_bus_info;  /* was resvd */
+} __attribute__ ((packed));
+
+struct FC_LDRV_INFO {
+       u8 NumLDrv;             /* No. of Log. Drvs configured. */
+       u8 recon_state[FC_MAX_LOGICAL_DRIVES / 8];
+       /* bit field for State of reconstruct */
+       u16 LDrvOpStatus[FC_MAX_LOGICAL_DRIVES / 8];
+       /* bit field Status of Long Operations. */
+
+       u32 LDrvSize[FC_MAX_LOGICAL_DRIVES];    /* Size of each log. Drv. */
+       u8 LDrvProp[FC_MAX_LOGICAL_DRIVES];
+       u8 LDrvState[FC_MAX_LOGICAL_DRIVES];    /* State of Logical Drives. */
+} __attribute__ ((packed));
+
+#define PREVSTAT_MASK   0xf0
+#define CURRSTAT_MASK   0x0f
+
+struct FC_PDRV_INFO {
+       u8 PDrvState[FC_MAX_PHYSICAL_DEVICES];  /* State of Phys Drvs. */
+} __attribute__ ((packed));
+
+struct FC_AdapterInq {
+       struct FC_ADP_INFO AdpInfo;
+       struct FC_LDRV_INFO LogdrvInfo;
+       struct FC_PDRV_INFO PhysdrvInfo;
+} __attribute__ ((packed));
+
+typedef struct FC_AdapterInq mega_RAIDINQ_FC;
+
+/********************************************
+ * NOTIFICATION
+ ********************************************/
+
+#define MAX_NOTIFY_SIZE     0x80
+#define CUR_NOTIFY_SIZE     sizeof(struct MegaRAID_Notify)
+
+/*
+ * Utilities declare this strcture size as ?? bytes. So more fields can
+ * be added in future.
+ */
+struct MegaRAID_Notify {
+       u32 globalCounter;      /* Any change increments this counter */
+
+       u8 paramCounter;        /* Indicates any params changed  */
+       u8 paramId;             /* Param modified - defined below */
+       u16 paramVal;           /* New val of last param modified */
+
+       u8 writeConfigCounter;  /* write config occurred */
+       u8 writeConfigRsvd[3];
+
+       u8 ldrvOpCounter;       /* Indicates ldrv op started/completed */
+       u8 ldrvOpId;            /* ldrv num */
+       u8 ldrvOpCmd;           /* ldrv operation - defined below */
+       u8 ldrvOpStatus;        /* status of the operation */
+
+       u8 ldrvStateCounter;    /* Indicates change of ldrv state */
+       u8 ldrvStateId;         /* ldrv num */
+       u8 ldrvStateNew;        /* New state */
+       u8 ldrvStateOld;        /* old state */
+
+       u8 pdrvStateCounter;    /* Indicates change of ldrv state */
+       u8 pdrvStateId;         /* pdrv id */
+       u8 pdrvStateNew;        /* New state */
+       u8 pdrvStateOld;        /* old state */
+
+       u8 pdrvFmtCounter;      /* Indicates pdrv format started/over */
+       u8 pdrvFmtId;           /* pdrv id */
+       u8 pdrvFmtVal;          /* format started/over */
+       u8 pdrvFmtRsvd;
+
+       u8 targXferCounter;     /* Indicates SCSI-2 Xfer rate change */
+       u8 targXferId;          /* pdrv Id  */
+       u8 targXferVal;         /* new Xfer params of last pdrv */
+       u8 targXferRsvd;
+
+       u8 fcLoopIdChgCounter;  /* Indicates loopid changed */
+       u8 fcLoopIdPdrvId;      /* pdrv id */
+       u8 fcLoopId0;           /* loopid on fc loop 0 */
+       u8 fcLoopId1;           /* loopid on fc loop 1 */
+
+       u8 fcLoopStateCounter;  /* Indicates loop state changed */
+       u8 fcLoopState0;        /* state of fc loop 0 */
+       u8 fcLoopState1;        /* state of fc loop 1 */
+       u8 fcLoopStateRsvd;
+} __attribute__ ((packed));
+
+/********************************************
+ * PARAM IDs in Notify struct
+ ********************************************/
+#define PARAM_RBLD_RATE                 0x01
+    /*--------------------------------------
+     * Param val =
+     *      byte 0: new rbld rate
+     *--------------------------------------*/
+#define PARAM_CACHE_FLUSH_INTERVAL      0x02
+    /*--------------------------------------
+     * Param val =
+     *      byte 0: new cache flush interval
+     *--------------------------------------*/
+#define PARAM_SENSE_ALERT             0x03
+    /*--------------------------------------
+     * Param val =
+     *      byte 0: last pdrv id causing chkcond
+     *--------------------------------------*/
+#define PARAM_DRIVE_INSERTED       0x04
+    /*--------------------------------------
+     * Param val =
+     *      byte 0: last pdrv id inserted
+     *--------------------------------------*/
+#define PARAM_BATTERY_STATUS       0x05
+    /*--------------------------------------
+     * Param val =
+     *      byte 0: battery status
+     *--------------------------------------*/
+
+/********************************************
+ * Ldrv operation cmd in Notify struct
+ ********************************************/
+#define LDRV_CMD_CHKCONSISTANCY         0x01
+#define LDRV_CMD_INITIALIZE     0x02
+#define LDRV_CMD_RECONSTRUCTION         0x03
+
+/********************************************
+ * Ldrv operation status in Notify struct
+ ********************************************/
+#define LDRV_OP_SUCCESS                 0x00
+#define LDRV_OP_FAILED          0x01
+#define LDRV_OP_ABORTED                 0x02
+#define LDRV_OP_CORRECTED       0x03
+#define LDRV_OP_STARTED                 0x04
+
+/********************************************
+ * Raid Logical drive states.
+ ********************************************/
+#define     RDRV_OFFLINE       0
+#define     RDRV_DEGRADED      1
+#define     RDRV_OPTIMAL       2
+#define     RDRV_DELETED       3
+
+/*******************************************
+ * Physical drive states.
+ *******************************************/
+#define     PDRV_UNCNF         0
+#define     PDRV_ONLINE                3
+#define     PDRV_FAILED                4
+#define     PDRV_RBLD          5
+
+/*******************************************
+ * Formal val in Notify struct
+ *******************************************/
+#define PDRV_FMT_START         0x01
+#define PDRV_FMT_OVER          0x02
+
+/********************************************
+ * FC Loop State in Notify Struct
+ ********************************************/
+#define ENQ_FCLOOP_FAILED      0
+#define ENQ_FCLOOP_ACTIVE      1
+#define ENQ_FCLOOP_TRANSIENT   2
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+#define M_RD_DMA_TYPE_NONE             0xFFFF
+#define M_RD_PTHRU_WITH_BULK_DATA      0x0001
+#define M_RD_PTHRU_WITH_SGLIST         0x0002
+#define M_RD_BULK_DATA_ONLY            0x0004
+#define M_RD_SGLIST_ONLY               0x0008
+#define M_RD_EPTHRU_WITH_BULK_DATA     0x0010
+#endif
+/********************************************
+ * ENQUIRY3
+ ********************************************/
+/*
+ * Utilities declare this strcture size as 1024 bytes. So more fields can
+ * be added in future.
+ */
+struct MegaRAID_Enquiry3 {
+       u32 dataSize;           /* current size in bytes (not including resvd) */
+
+       struct MegaRAID_Notify notify;
+
+       u8 notifyRsvd[MAX_NOTIFY_SIZE - CUR_NOTIFY_SIZE];
+
+       u8 rbldRate;            /* Rebuild rate (0% - 100%) */
+       u8 cacheFlushInterval;  /* In terms of Seconds */
+       u8 senseAlert;
+       u8 driveInsertedCount;  /* drive insertion count */
+
+       u8 batteryStatus;
+       u8 numLDrv;             /* No. of Log Drives configured */
+       u8 reconState[FC_MAX_LOGICAL_DRIVES / 8];       /* State of reconstruct */
+       u16 lDrvOpStatus[FC_MAX_LOGICAL_DRIVES / 8];    /* log. Drv Status */
+
+       u32 lDrvSize[FC_MAX_LOGICAL_DRIVES];    /* Size of each log. Drv */
+       u8 lDrvProp[FC_MAX_LOGICAL_DRIVES];
+       u8 lDrvState[FC_MAX_LOGICAL_DRIVES];    /* State of Logical Drives */
+       u8 pDrvState[FC_MAX_PHYSICAL_DEVICES];  /* State of Phys. Drvs. */
+       u16 physDrvFormat[FC_MAX_PHYSICAL_DEVICES / 16];
+
+       u8 targXfer[80];        /* phys device transfer rate */
+       u8 pad1k[263];          /* 761 + 263reserved = 1024 bytes total size */
+} __attribute__ ((packed));
+typedef struct MegaRAID_Enquiry3 mega_Enquiry3;
+
+/* Structures */
+typedef struct _mega_ADP_INFO {
+       u8 MaxConcCmds;
+       u8 RbldRate;
+       u8 MaxTargPerChan;
+       u8 ChanPresent;
+       u8 FwVer[4];
+       u16 AgeOfFlash;
+       u8 ChipSetValue;
+       u8 DramSize;
+       u8 CacheFlushInterval;
+       u8 BiosVer[4];
+       u8 resvd[7];
+} mega_ADP_INFO;
+
+typedef struct _mega_LDRV_INFO {
+       u8 NumLDrv;
+       u8 resvd[3];
+       u32 LDrvSize[MAX_LOGICAL_DRIVES];
+       u8 LDrvProp[MAX_LOGICAL_DRIVES];
+       u8 LDrvState[MAX_LOGICAL_DRIVES];
+} mega_LDRV_INFO;
+
+typedef struct _mega_PDRV_INFO {
+       u8 PDrvState[MAX_PHYSICAL_DRIVES];
+       u8 resvd;
+} mega_PDRV_INFO;
+
+/* RAID inquiry: Mailbox command 0x5*/
+typedef struct _mega_RAIDINQ {
+       mega_ADP_INFO AdpInfo;
+       mega_LDRV_INFO LogdrvInfo;
+       mega_PDRV_INFO PhysdrvInfo;
+} mega_RAIDINQ;
+
+/* Passthrough command: Mailbox command 0x3*/
+typedef struct mega_passthru {
+       u8 timeout:3;           /* 0=6sec/1=60sec/2=10min/3=3hrs */
+       u8 ars:1;
+       u8 reserved:3;
+       u8 islogical:1;
+       u8 logdrv;              /* if islogical == 1 */
+       u8 channel;             /* if islogical == 0 */
+       u8 target;              /* if islogical == 0 */
+       u8 queuetag;            /* unused */
+       u8 queueaction;         /* unused */
+       u8 cdb[MAX_CDB_LEN];
+       u8 cdblen;
+       u8 reqsenselen;
+       u8 reqsensearea[MAX_REQ_SENSE_LEN];
+       u8 numsgelements;
+       u8 scsistatus;
+       u32 dataxferaddr;
+       u32 dataxferlen;
+} mega_passthru;
+
+/*
+ * Extended passthru: support CDB > 10 bytes
+ */
+typedef struct {
+       u8 timeout:3;           /* 0=6sec/1=60sec/2=10min/3=3hrs */
+       u8 ars:1;
+       u8 rsvd1:1;
+       u8 cd_rom:1;
+       u8 rsvd2:1;
+       u8 islogical:1;
+
+       u8 logdrv;              /* if islogical == 1 */
+       u8 channel;             /* if islogical == 0 */
+       u8 target;              /* if islogical == 0 */
+
+       u8 queuetag;            /* unused */
+       u8 queueaction;         /* unused */
+
+       u8 cdblen;
+       u8 rsvd3;
+       u8 cdb[16];
+
+       u8 numsgelements;
+       u8 status;
+       u8 reqsenselen;
+       u8 reqsensearea[MAX_REQ_SENSE_LEN];
+       u8 rsvd4;
+
+       u32 dataxferaddr;
+       u32 dataxferlen;
+}mega_ext_passthru;
+
+struct _mega_mailbox {
+       /* 0x0 */ u8 cmd;
+       /* 0x1 */ u8 cmdid;
+       /* 0x2 */ u16 numsectors;
+       /* 0x4 */ u32 lba;
+       /* 0x8 */ u32 xferaddr;
+       /* 0xC */ u8 logdrv;
+       /* 0xD */ u8 numsgelements;
+       /* 0xE */ u8 resvd;
+       /* 0xF */ u8 busy;
+       /* 0x10 */ u8 numstatus;
+       /* 0x11 */ u8 status;
+       /* 0x12 */ u8 completed[46];
+       volatile u8 mraid_poll;
+       volatile u8 mraid_ack;
+       u8 pad[16];             /* for alignment purposes */
+} __attribute__ ((packed));
+typedef struct _mega_mailbox mega_mailbox;
+
+typedef struct {
+       u32 xferSegment_lo;
+       u32 xferSegment_hi;
+       mega_mailbox mailbox;
+} mega_mailbox64;
+
+typedef struct _mega_ioctl_mbox {
+       /* 0x0 */ u8 cmd;
+       /* 0x1 */ u8 cmdid;
+       /* 0x2 */ u8 channel;
+       /* 0x3 */ u8 param;
+       /* 0x4 */ u8 pad[4];
+       /* 0x8 */ u32 xferaddr;
+       /* 0xC */ u8 logdrv;
+       /* 0xD */ u8 numsgelements;
+       /* 0xE */ u8 resvd;
+       /* 0xF */ u8 busy;
+       /* 0x10 */ u8 numstatus;
+       /* 0x11 */ u8 status;
+       /* 0x12 */ u8 completed[46];
+       u8 mraid_poll;
+       u8 mraid_ack;
+       u8 malign[16];
+} mega_ioctl_mbox;
+
+typedef struct _mega_64sglist32 {
+       u64 address;
+       u32 length;
+} __attribute__ ((packed)) mega_64sglist;
+
+typedef struct _mega_sglist {
+       u32 address;
+       u32 length;
+} mega_sglist;
+
+/* Queued command data */
+typedef struct _mega_scb mega_scb;
+
+struct _mega_scb {
+       int idx;
+       u32 state;
+       u32 isrcount;
+       u8 mboxData[16];
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+       u32 dma_type;
+       dma_addr_t dma_h_bulkdata;      /*Dma handle for bulk data transfter */
+       u32 dma_direction;      /*Dma direction */
+       dma_addr_t dma_h_sgdata;        /*Dma handle for the sglist structure */
+       dma_addr_t dma_h_sglist[MAX_SGLIST];    /*Dma handle for all SGL elements */
+       u8 sglist_count;
+       dma_addr_t dma_sghandle64;
+       dma_addr_t dma_passthruhandle64;
+       dma_addr_t dma_ext_passthruhandle64;
+       dma_addr_t dma_bounce_buffer;
+       u8 *bounce_buffer;
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+       mega_passthru *pthru;
+       mega_ext_passthru *epthru;
+#else
+       mega_passthru pthru;
+       mega_ext_passthru epthru;
+#endif
+
+       Scsi_Cmnd *SCpnt;
+       mega_sglist *sgList;
+       mega_64sglist *sg64List;
+#if 0
+       struct semaphore ioctl_sem;
+#endif
+       void *buff_ptr;
+       u32 iDataSize;
+       mega_scb *next;
+};
+
+/* internal locking by the queue manipulting routines */
+#define INTERNAL_LOCK   0
+/* external locking by the queue manipulting routines */
+#define EXTERNAL_LOCK   1
+#define NO_LOCK                2
+#define INTR_ENB       0       /* do not disable interrupt while manipulating */
+#define INTR_DIS       1       /* disable interrupt while manipulating */
+
+#define NVIRT_CHAN             4       /* # of virtual channels to represent 60 logical
+                                                       drives */
+
+/* Per-controller data */
+typedef struct _mega_host_config {
+       u8 numldrv;
+       u32 flag;
+
+#ifdef __LP64__
+       u64 base;
+#else
+       u32 base;
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+       dma_addr_t dma_handle64, adjdmahandle64;
+       struct pci_dev *dev;
+#endif
+
+       mega_scb *qFreeH;
+       mega_scb *qFreeT;
+       spinlock_t lock_free;
+
+       mega_scb *qPendingH;
+       mega_scb *qPendingT;
+       spinlock_t lock_pend;
+
+       Scsi_Cmnd *qCompletedH;
+       Scsi_Cmnd *qCompletedT;
+       spinlock_t lock_scsicmd;
+
+       u32 qFcnt;
+       u32 qPcnt;
+       u32 qCcnt;
+
+       unsigned long nReads[FC_MAX_LOGICAL_DRIVES];
+       unsigned long nReadBlocks[FC_MAX_LOGICAL_DRIVES];
+       unsigned long nWrites[FC_MAX_LOGICAL_DRIVES];
+       unsigned long nWriteBlocks[FC_MAX_LOGICAL_DRIVES];
+       unsigned long nInterrupts;
+       /* Host adapter parameters */
+       u8 fwVer[7];
+       u8 biosVer[7];
+
+       struct Scsi_Host *host;
+
+       volatile mega_mailbox64 *mbox64;        /* ptr to beginning of 64-bit mailbox */
+       volatile mega_mailbox *mbox;    /* ptr to beginning of standard mailbox */
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+/* ptr to beginning of standard mailbox */
+       volatile mega_mailbox64 *mailbox64ptr;
+#else
+       volatile mega_mailbox64 mailbox64;
+#endif
+
+       volatile u8 mega_buffer[2 * 1024L];
+       volatile megaRaidProductInfo productInfo;
+
+       u8 max_cmds;
+       mega_scb scbList[MAX_COMMANDS];
+
+#if XENO_KILLED
+#define PROCBUFSIZE 4096
+       char procbuf[PROCBUFSIZE];
+       int procidx;
+       struct proc_dir_entry *controller_proc_dir_entry;
+       struct proc_dir_entry *proc_read, *proc_stat, *proc_status, *proc_mbox;
+#endif
+
+       int             support_ext_cdb;
+
+       u8              boot_ldrv_enabled;      /* boot from logical drive */
+       u8              boot_ldrv;                      /* boot logical drive */
+       u8              boot_pdrv_enabled;      /* boot from physical drive */
+       u8              boot_pdrv_ch;           /* boot physical drive channel */
+       u8              boot_pdrv_tgt;          /* boot physical drive target */
+
+       int             support_random_del;     /* Do we support random deletion of logdrvs */
+       int             read_ldidmap;   /* set after logical drive deltion. The logical
+                                                               drive number must be read from the map */
+       int             quiescent;      /* a stage reached when delete logical drive needs to
+                                                  be done. Stop sending requests to the hba till
+                                                  delete operation is completed */
+
+       mega_scb        *int_qh;        /* commands are queued in the internal queue */
+       mega_scb        *int_qt;        /* while the hba is quiescent */
+       int                     int_qlen;
+       char            logdrv_chan[MAX_CHANNEL+NVIRT_CHAN]; /* logical drive are on
+                                                                                                                what channels. */
+       int                     mega_ch_class;
+} mega_host_config;
+
+typedef struct _driver_info {
+       int size;
+       ulong version;
+} mega_driver_info;
+
+/*
+ * User ioctl structure.
+ * This structure will be used for Traditional Method ioctl interface
+ * commands (M_RD_IOCTL_CMD),Alternate Buffer Method (M_RD_IOCTL_CMD_NEW) 
+ * ioctl commands and the Driver ioctls(M_RD_DRIVER_IOCTL_INTERFACE).
+ * The Driver ioctl interface handles the commands at
+ * the driver level, without being sent to the card.
+ */
+#define MEGADEVIOC      0x84
+
+/* system call imposed limit. Change accordingly */
+#define IOCTL_MAX_DATALEN       4096
+
+#pragma pack(1)
+struct uioctl_t {
+       u32 inlen;
+       u32 outlen;
+       union {
+               u8 fca[16];
+               struct {
+                       u8 opcode;
+                       u8 subopcode;
+                       u16 adapno;
+#if BITS_PER_LONG == 32
+                       u8 *buffer;
+                       u8 pad[4];
+#endif
+#if BITS_PER_LONG == 64
+                       u8 *buffer;
+#endif
+                       u32 length;
+               } fcs;
+       } ui;
+       u8 mbox[18];            /* 16 bytes + 2 status bytes */
+       mega_passthru pthru;
+#if BITS_PER_LONG == 32
+       char *data;             /* buffer <= 4096 for 0x80 commands */
+       char pad[4];
+#endif
+#if BITS_PER_LONG == 64
+       char *data;
+#endif
+};
+#pragma pack()
+
+/*
+ * struct mcontroller is used to pass information about the controllers in the
+ * system. Its upto the application how to use the information. We are passing
+ * as much info about the cards as possible and useful. Before issuing the
+ * call to find information about the cards, the applicaiton needs to issue a
+ * ioctl first to find out the number of controllers in the system.
+ */
+#define MAX_CONTROLLERS 32
+
+struct mcontroller {
+       u64 base;
+       u8 irq;
+       u8 numldrv;
+       u8 pcibus;
+       u16 pcidev;
+       u8 pcifun;
+       u16 pciid;
+       u16 pcivendor;
+       u8 pcislot;
+       u32 uid;
+};
+
+struct mbox_passthru {
+       u8 cmd;
+       u8 cmdid;
+       u16 pad1;
+       u32 pad2;
+       u32 dataxferaddr;
+       u8 pad3;
+       u8 pad4;
+       u8 rsvd;
+       u8 mboxbusy;
+       u8 nstatus;
+       u8 status;
+};
+
+/*
+ * Defines for Driver IOCTL interface, Op-code:M_RD_DRIVER_IOCTL_INTERFACE
+ */
+#define MEGAIOC_MAGIC          'm'
+#define MEGAIOCCMD             _IOWR(MEGAIOC_MAGIC, 0) /* Mega IOCTL command */
+
+#define MEGAIOC_QNADAP         'm'     /* Query # of adapters */
+#define MEGAIOC_QDRVRVER       'e'     /* Query driver version */
+#define MEGAIOC_QADAPINFO      'g'     /* Query adapter information */
+#define MKADAP(adapno)         (MEGAIOC_MAGIC << 8 | (adapno) )
+#define GETADAP(mkadap)                ( (mkadap) ^ MEGAIOC_MAGIC << 8 )
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) /*0x20300 */
+extern struct proc_dir_entry proc_scsi_megaraid;
+#endif
+
+/* For Host Re-Ordering */
+#define MAX_CONTROLLERS        32
+
+struct mega_hbas {
+       int is_bios_enabled;
+       mega_host_config *hostdata_addr;
+};
+
+#define                IS_BIOS_ENABLED         0x62
+#define                GET_BIOS                0x01
+#define                CHNL_CLASS              0xA9
+#define                GET_CHNL_CLASS  0x00
+#define                SET_CHNL_CLASS  0x01
+#define                CH_RAID                 0x01
+#define                CH_SCSI                 0x00
+
+
+#define BIOS_PVT_DATA          0x40
+#define GET_BIOS_PVT_DATA      0x00
+
+#pragma pack(1)
+struct private_bios_data {
+       u8              geometry:4;             /*
+                                                        * bits 0-3 - BIOS geometry
+                                                        * 0x0001 - 1GB
+                                                        * 0x0010 - 2GB
+                                                        * 0x1000 - 8GB
+                                                        * Others values are invalid
+                                                        */
+       u8              unused:4;               /* bits 4-7 are unused */
+       u8              boot_drv;               /*
+                                                        * logical/physical drive set as boot drive
+                                                        * 0..7 - for 8LD cards
+                                                        * 0..39 - for 40LD cards
+                                                        */
+       u8              rsvd[12];
+       u16             cksum;                  /* 0-(sum of first 13 bytes of this structure) */
+};
+#pragma pack()
+
+/*
+ * Command for random deletion of logical drives
+ */
+#define        FC_DEL_LOGDRV           0xA4    /* f/w command */
+#define        OP_SUP_DEL_LOGDRV       0x2A    /* is feature supported */
+#define OP_GET_LDID_MAP                0x18    /* get logdrv id and logdrv number map */
+#define OP_DEL_LOGDRV          0x1C    /* delete logical drive */
+
+/*================================================================
+ *
+ *                    Function prototypes
+ *
+ *================================================================
+ */
+const char *megaraid_info (struct Scsi_Host *);
+int megaraid_detect (Scsi_Host_Template *);
+int megaraid_release (struct Scsi_Host *);
+int megaraid_command (Scsi_Cmnd *);
+int megaraid_abort (Scsi_Cmnd *);
+int megaraid_reset (Scsi_Cmnd *, unsigned int);
+int megaraid_queue (Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
+int megaraid_biosparam (Disk *, kdev_t, int *);
+#if 0
+int megaraid_proc_info (char *buffer, char **start, off_t offset,
+                       int length, int hostno, int inout);
+#endif
+static int megaIssueCmd (mega_host_config * megaCfg, u_char * mboxData,
+                        mega_scb * scb, int intr);
+static int mega_build_sglist (mega_host_config * megaCfg, mega_scb * scb,
+                             u32 * buffer, u32 * length);
+static int mega_busyWaitMbox (mega_host_config *);
+static int mega_runpendq (mega_host_config *);
+static void mega_rundoneq (mega_host_config *);
+static void mega_cmd_done (mega_host_config *, mega_scb *, int);
+static inline void mega_freeSgList (mega_host_config * megaCfg);
+static void mega_Convert8ldTo40ld (mega_RAIDINQ * inquiry,
+                                  mega_Enquiry3 * enquiry3,
+                                  megaRaidProductInfo * productInfo);
+
+static int megaraid_reboot_notify (struct notifier_block *,
+                                  unsigned long, void *);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)  
+static mega_scb *mega_ioctl (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt);
+static void mega_build_kernel_sg (char *barea, ulong xfersize, mega_scb * pScb,
+                          mega_ioctl_mbox * mbox);
+#endif
+
+static int megadev_open (struct inode *, struct file *);
+static int megadev_ioctl_entry (struct inode *, struct file *,
+                               unsigned int, unsigned long);
+static int megadev_ioctl (struct inode *, struct file *,
+                         unsigned int, unsigned long);
+static mega_scb *megadev_doioctl (mega_host_config *, Scsi_Cmnd *);
+static int megadev_close (struct inode *, struct file *);
+static void megadev_ioctl_done (Scsi_Cmnd *);
+static int mega_init_scb (mega_host_config *);
+static void enq_scb_freelist (mega_host_config *, mega_scb *,
+                             int lock, int intr);
+
+static int mega_is_bios_enabled (mega_host_config *);
+static void mega_reorder_hosts (void);
+static void mega_swap_hosts (struct Scsi_Host *, struct Scsi_Host *);
+
+#if 0
+static void mega_create_proc_entry (int index, struct proc_dir_entry *);
+#endif
+static int mega_support_ext_cdb(mega_host_config *);
+static mega_passthru* mega_prepare_passthru(mega_host_config *, mega_scb *,
+               Scsi_Cmnd *, int, int);
+static mega_ext_passthru* mega_prepare_extpassthru(mega_host_config *,
+               mega_scb *, Scsi_Cmnd *, int, int);
+static void mega_enum_raid_scsi(mega_host_config *);
+static int mega_partsize(Disk *, kdev_t, int *);
+static void mega_get_boot_drv(mega_host_config *);
+static int mega_get_ldrv_num(mega_host_config *, Scsi_Cmnd *, int);
+static int mega_support_random_del(mega_host_config *);
+static int mega_del_logdrv(mega_host_config *, int);
+static int mega_do_del_logdrv(mega_host_config *, int);
+
+#endif
+
+/* vi: set ts=4: */
diff --git a/xen/include/xeno/version.h b/xen/include/xeno/version.h
new file mode 100644 (file)
index 0000000..a0bbfa9
--- /dev/null
@@ -0,0 +1,2 @@
+#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
+#define LINUX_VERSION_CODE KERNEL_VERSION(2,4,21)